No Description

test-context.js 3.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. //@flow
  2. let tests: Array<TestCase> = []
  3. let RCTContext: ReactElement = null
  4. let props:any = {}
  5. let timeout = 3000
  6. export default class TestContext {
  7. static setTimeout (val) {
  8. timeout = val
  9. }
  10. static config(config) {
  11. return TestContext.describe.bind(config)
  12. }
  13. /**
  14. * Calling this method will push a test case into task queue.
  15. * @param {String} desc Description of test case.
  16. * @param {Function:Promise<any>} fn Body of test case, this function
  17. * should return a promise.
  18. * @return {void}
  19. */
  20. static describe (...args) {
  21. let { group, timeout, expand, run } = this || {}
  22. let desc, config, fn
  23. if([...args].length === 2) {
  24. [desc, fn] = [...args]
  25. }
  26. else if ([...args].length === 3) {
  27. [desc, config, fn] = [...args]
  28. group = config.group || group
  29. timeout = config.timeout || timeout
  30. expand = config.expand || expand
  31. run = config.run || run
  32. }
  33. let ctx = {
  34. group : group || 'common',
  35. status : 'waiting',
  36. run : run === false ? false : true,
  37. result : null,
  38. asserts : [],
  39. timeout : timeout || 3000,
  40. expired : false,
  41. running : false,
  42. executed : false,
  43. expand : expand || false,
  44. desc,
  45. fn,
  46. sn : tests.length,
  47. start : (i) => {
  48. TestContext.startTest.bind(
  49. tests[i],
  50. TestContext.update.bind(TestContext, i),
  51. TestContext.updateInternal.bind(TestContext, i)
  52. )()
  53. }
  54. }
  55. tests.push(ctx)
  56. }
  57. static prop (name:string, val:any):TestContext {
  58. if(name === undefined && val === undefined)
  59. return props
  60. if(val === undefined)
  61. return props[name]
  62. props[name] = val
  63. return TestContext
  64. }
  65. /**
  66. * Run test cases in sequence.
  67. * @param {ReactElement} context ReactElement instance context.
  68. * @return {void}
  69. */
  70. static run (context:ReactElement) {
  71. RCTContext = context
  72. let promise = Promise.resolve()
  73. // run test case sequently
  74. for(let i in tests) {
  75. if(tests[i].run === false) {
  76. tests[i].status = 'skipped'
  77. tests[i].executed = true
  78. promise = Promise.resolve()
  79. continue
  80. }
  81. promise = promise.then(
  82. TestContext.startTest.bind(
  83. tests[i],
  84. TestContext.update.bind(TestContext, i),
  85. TestContext.updateInternal.bind(TestContext, i)
  86. ))
  87. }
  88. return promise
  89. }
  90. static startTest(update, updateInternal, data) {
  91. return new Promise((resolve, reject) => {
  92. let expired = false
  93. updateInternal({
  94. running : true,
  95. })
  96. // set timeout timer
  97. let tm = setTimeout(() => {
  98. updateInternal({
  99. expired : true,
  100. executed : true,
  101. running : false
  102. })
  103. resolve('ETIMEOUT')
  104. }, this.timeout)
  105. // run test body
  106. new Promise((done) => {
  107. this.fn.bind(this)(update, done)
  108. })
  109. .then((...res) => {
  110. if(!expired) {
  111. clearTimeout(tm)
  112. updateInternal({
  113. executed : true,
  114. running : false
  115. })
  116. resolve(...res)
  117. }
  118. }).catch((err) => {
  119. updateInternal({
  120. executed : true,
  121. running : false
  122. })
  123. })
  124. })
  125. }
  126. /**
  127. * Update test task result of given index.
  128. * @param {number} i Index of test case to be updated.
  129. * @param {ReactElement<Info | Assert>} ...data Assertion or Info of test.
  130. * @return {void}
  131. */
  132. static update(i, ...data) {
  133. let test = tests[i]
  134. let result = test.result || []
  135. Object.assign(test, {result : [...result, ...data]})
  136. RCTContext.forceUpdate()
  137. }
  138. static getTests() {
  139. return tests
  140. }
  141. /**
  142. * Update test result for testkit internal use
  143. * @param {[type]} i Index of test case to be updated.
  144. * @param {TestCaseContext} result Test case object
  145. * @return {void}
  146. */
  147. static updateInternal(i, result) {
  148. Object.assign(tests[i], result)
  149. RCTContext.forceUpdate()
  150. }
  151. }