Extract and set form values through the DOM—no frameworks required! https://github.com/TheoryOfNekomata/formxtra
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

146 line
3.5 KiB

  1. /// <reference types="cypress" />
  2. /// <reference types="cypress-jest-adapter" />
  3. /// <reference types="node" />
  4. import * as fs from 'fs'
  5. import * as path from 'path'
  6. type TestFn = (form: HTMLFormElement, submitter: HTMLButtonElement | HTMLInputElement, after: Record<string, string> | string) => unknown
  7. class JSDOMJQuery {
  8. private selectedElements: Node[]
  9. constructor(elements: NodeList) {
  10. this.selectedElements = Array.from(elements)
  11. }
  12. type(s: string) {
  13. this.selectedElements.forEach((el: any) => {
  14. if (el.tagName === 'TEXTAREA') {
  15. el.innerText = s
  16. el.value = s
  17. return
  18. }
  19. el.setAttribute('value', s)
  20. el.value = s
  21. })
  22. return this
  23. }
  24. check() {
  25. this.selectedElements.forEach((el: any) => {
  26. el.setAttribute('checked', '')
  27. el.checked = true
  28. })
  29. return this
  30. }
  31. select(v: string) {
  32. this.selectedElements.forEach((el: any) => {
  33. const option: any = Array.from(el.querySelectorAll('option')).find((o: any) => o.textContent === v)
  34. option.setAttribute('selected', '')
  35. el.value = option.value
  36. })
  37. return this
  38. }
  39. last() {
  40. this.selectedElements = this.selectedElements.slice(-1)
  41. return this
  42. }
  43. then(fn: (...args: unknown[]) => unknown) {
  44. fn(this.selectedElements)
  45. return this
  46. }
  47. click() {
  48. return this
  49. }
  50. submit() {
  51. return this
  52. }
  53. }
  54. class JSDOMDummyCypress {
  55. private currentElement = window.document;
  56. get(q: string) {
  57. return new JSDOMJQuery(this.currentElement.querySelectorAll(q));
  58. }
  59. }
  60. export const setup = (template: string) => {
  61. if (typeof cy !== 'undefined') {
  62. return () => {
  63. cy.intercept({ url: '/' }, { fixture: `templates/${template}.html` });
  64. cy.intercept({ url: '/?*' }, { fixture: `templates/${template}.html` }).as('submitted');
  65. }
  66. }
  67. return async () => {
  68. const templatePath = path.join('test', 'fixtures', 'templates', `${template}.html`)
  69. const templateRaw = await fs.promises.readFile(templatePath)
  70. window.document.open(undefined, undefined, undefined, true)
  71. window.document.write(templateRaw.toString('utf-8'))
  72. window.document.close()
  73. }
  74. }
  75. export const test = (retrieveSubmitterFn: (wrapper: any) => any, testFn: TestFn, expectedValue: Record<string, string> | string) => {
  76. let form: HTMLFormElement
  77. let submitter: HTMLButtonElement | HTMLInputElement
  78. if (typeof cy !== 'undefined') {
  79. cy
  80. .visit('/')
  81. .get('form')
  82. .then((formResult: any) => {
  83. [form] = Array.from(formResult);
  84. })
  85. retrieveSubmitterFn(cy)
  86. .then((submitterQueryEl: any) => {
  87. [submitter] = Array.from(submitterQueryEl as any[])
  88. })
  89. .click()
  90. cy
  91. .wait('@submitted')
  92. .location('search')
  93. .then(search => {
  94. testFn(form, submitter, search)
  95. })
  96. } else {
  97. retrieveSubmitterFn(new JSDOMDummyCypress())
  98. .then((submitterQueryEl: any) => {
  99. [submitter] = Array.from(submitterQueryEl as any[]);
  100. [form] = Array.from(window.document.getElementsByTagName('form'))
  101. testFn(form, submitter, expectedValue)
  102. })
  103. .click();
  104. }
  105. }
  106. export const makeSearchParams = (beforeValues: Record<string, unknown> | string) => {
  107. switch (typeof (beforeValues as unknown)) {
  108. case 'string':
  109. return new URLSearchParams(beforeValues as string)
  110. case 'object':
  111. return Object
  112. .entries(beforeValues)
  113. .filter(([k]) => k.trim().length > 0)
  114. .reduce(
  115. (beforeSearchParams, [key, value]) => {
  116. const theValue = !Array.isArray(value) ? [value] : value
  117. theValue.forEach(v => {
  118. beforeSearchParams.append(key, v)
  119. })
  120. return beforeSearchParams
  121. },
  122. new URLSearchParams()
  123. )
  124. default:
  125. break
  126. }
  127. throw new TypeError('Invalid parameter.')
  128. }