Browse Source

Add config API to testkit

Ben Hsieh 8 years ago
parent
commit
c0a9990538

+ 97
- 39
test/react-native-testkit/components/reporter.js View File

6
   View,
6
   View,
7
   Platform,
7
   Platform,
8
   ScrollView,
8
   ScrollView,
9
+  ListView,
9
   Image,
10
   Image,
11
+  TouchableOpacity,
12
+  RecyclerViewBackedScrollView,
10
 } from 'react-native';
13
 } from 'react-native';
11
 
14
 
12
 import Assert from './assert.js'
15
 import Assert from './assert.js'
14
 
17
 
15
 export default class Reporter extends Component {
18
 export default class Reporter extends Component {
16
 
19
 
20
+  constructor(props:any) {
21
+    super(props)
22
+    this.tests = {
23
+      common : []
24
+    }
25
+    this.testGroups = ['common']
26
+    this.ds = null
27
+    this.updateDataSource()
28
+
29
+  }
30
+
31
+  componentWillUpdate(nextProps, nextState) {
32
+    this.updateDataSource()
33
+  }
34
+
17
   render() {
35
   render() {
36
+
18
     return (
37
     return (
19
-      <ScrollView key="rn-test-scroller" style={styles.container}>
20
-        {this.renderTests()}
21
-      </ScrollView>)
38
+      <ListView
39
+        style={styles.container}
40
+        dataSource={this.ds}
41
+        renderRow={this.renderTest.bind(this)}
42
+        renderScrollComponent={props => <RecyclerViewBackedScrollView {...props} />}
43
+        renderSectionHeader={(data, id) => {
44
+          return (
45
+            <View style={styles.sectionHeader}>
46
+              <Text style={styles.sectionText}>{id}</Text>
47
+            </View>
48
+          )
49
+        }}
50
+      />)
22
   }
51
   }
23
 
52
 
24
-  renderTests() {
53
+  renderTest(t) {
54
+    let pass = true
55
+    let foundActions = false
25
     let tests = RNTEST.TestContext.getTests()
56
     let tests = RNTEST.TestContext.getTests()
26
-    return tests.map((t, i) => {
27
 
57
 
28
-      let pass = true
29
-      let foundActions = false
58
+    if(Array.isArray(t.result) && !t.expired) {
59
+      t.result = t.result.map((r) => {
60
+        if(r.type.name === 'Assert' || r.type.name === 'Info') {
61
+          foundActions = true
62
+          let comp = r.props.comparer ? r.props.comparer(r.props.expect, r.props.actual) : (r.props.actual === r.props.expect)
63
+          pass = pass && comp
64
+        }
65
+        return React.cloneElement(r, {desc : r.key})
66
+      })
67
+    }
68
+    if(tests[t.sn].running)
69
+      t.status = 'running'
70
+    else if(tests[t.sn].executed) {
71
+      t.status = foundActions ? (pass ? 'pass' : 'fail') : 'skipped'
72
+      t.status = t.expired ? 'timeout' : t.status
73
+    }
74
+    else
75
+      t.status = 'waiting'
30
 
76
 
31
-      if(Array.isArray(t.result) && !t.expired) {
32
-        t.result = t.result.map((r) => {
33
-          if(r.type.name === 'Assert' || r.type.name === 'Info') {
34
-            foundActions = true
35
-            let comp = r.props.comparer ? r.props.comparer(r.props.expect, r.props.actual) : (r.props.actual === r.props.expect)
36
-            pass = pass && comp
37
-          }
38
-          return React.cloneElement(r, {desc : r.key})
39
-        })
40
-      }
41
-      if(tests[i].running)
42
-        t.status = 'running'
43
-      else if(tests[i].executed) {
44
-        t.status = foundActions ? (pass ? 'pass' : 'fail') : 'skipped'
45
-        t.status = t.expired ? 'timeout' : t.status
77
+    return (
78
+      <TouchableOpacity onPress={()=>{
79
+          t.start(t.sn)
80
+        }}>
81
+        <View key={'rn-test-' + t.desc} style={{
82
+          borderBottomWidth : 1.5,
83
+          borderColor : '#DDD',
84
+        }}>
85
+          <View key={t.desc} style={{
86
+            alignItems : 'center',
87
+            flexDirection : 'row'
88
+          }}>
89
+            <Text style={[styles.badge, {flex : 1, borderWidth : 0, textAlign : 'left'}]}>{t.desc}</Text>
90
+            <Text style={[styles.badge, this.getBadge(t.status)]}>{t.status}</Text>
91
+          </View>
92
+          <View key={t.desc + '-result'} style={{backgroundColor : '#F4F4F4'}}>
93
+            {t.expand ? t.result : (t.status === 'pass' ? null : t.result)}
94
+          </View>
95
+        </View>
96
+      </TouchableOpacity>)
97
+  }
98
+
99
+  updateDataSource() {
100
+    this.tests = {
101
+      common : []
102
+    }
103
+    this.testGroups = ['common']
104
+    RNTEST.TestContext.getTests().forEach((t) => {
105
+      if(t.group) {
106
+        if(!this.tests[t.group]) {
107
+          this.testGroups.push(t.group)
108
+          this.tests[t.group] = []
109
+        }
110
+        this.tests[t.group].push(t)
46
       }
111
       }
47
       else
112
       else
48
-        t.status = 'waiting'
113
+        this.tests.common.push(t)
114
+    })
49
 
115
 
50
-      return (<View key={'rn-test-' + t.desc} style={{
51
-        borderBottomWidth : 1.5,
52
-        borderColor : '#DDD',
53
-      }}>
54
-        <View key={t.desc} style={{
55
-          alignItems : 'center',
56
-          flexDirection : 'row'
57
-        }}>
58
-          <Text style={[styles.badge, {flex : 1, borderWidth : 0, textAlign : 'left'}]}>{t.desc}</Text>
59
-          <Text style={[styles.badge, this.getBadge(t.status)]}>{t.status}</Text>
60
-        </View>
61
-        <View key={t.desc + '-result'} style={{backgroundColor : '#F4F4F4'}}>
62
-          {t.result}
63
-        </View>
64
-      </View>)
116
+    let listDataSource = new ListView.DataSource({
117
+      rowHasChanged : (r1, r2) => r1 !== r2,
118
+      sectionHeaderHasChanged: (s1, s2) => s1 !== s2
65
     })
119
     })
120
+    this.ds = listDataSource.cloneWithRowsAndSections(this.tests, this.testGroups)
66
   }
121
   }
67
 
122
 
68
   getBadge(status: 'waiting' | 'running' | 'pass' | 'fail' | 'timeout') {
123
   getBadge(status: 'waiting' | 'running' | 'pass' | 'fail' | 'timeout') {
74
 const styles = StyleSheet.create({
129
 const styles = StyleSheet.create({
75
   container: {
130
   container: {
76
     flex: 1,
131
     flex: 1,
77
-    marginTop : 40,
78
   },
132
   },
79
   badge : {
133
   badge : {
80
     margin : 16,
134
     margin : 16,
87
     borderColor : '#AAAAAA',
141
     borderColor : '#AAAAAA',
88
     color : '#AAAAAA'
142
     color : '#AAAAAA'
89
   },
143
   },
144
+  sectionHeader : {
145
+    padding : 16,
146
+    backgroundColor : '#F4F4F4',
147
+  },
90
   waiting: {
148
   waiting: {
91
     borderColor : '#AAAAAA',
149
     borderColor : '#AAAAAA',
92
     color : '#AAAAAA'
150
     color : '#AAAAAA'

+ 2
- 1
test/react-native-testkit/index.js View File

4
 import Assert from './components/assert'
4
 import Assert from './components/assert'
5
 import Info from './components/info'
5
 import Info from './components/info'
6
 
6
 
7
-const { describe, run, prop } = TestContext
7
+const { describe, run, prop, config } = TestContext
8
 
8
 
9
 export default {
9
 export default {
10
   TestContext,
10
   TestContext,
11
   Reporter,
11
   Reporter,
12
   Info,
12
   Info,
13
   Assert,
13
   Assert,
14
+  config,
14
   Comparer,
15
   Comparer,
15
   describe,
16
   describe,
16
   run,
17
   run,

+ 7
- 0
test/react-native-testkit/lib/comparer.js View File

5
   typeof : (a, b) => typeof a === b,
5
   typeof : (a, b) => typeof a === b,
6
   IsNull : (a, b) => a === null,
6
   IsNull : (a, b) => a === null,
7
   exists : (a, b) => a,
7
   exists : (a, b) => a,
8
+  equalToArray : (a, b) => {
9
+    if(!Array.isArray(a) && Array.isArray(b))
10
+      return false
11
+    return (a.length == b.length) && a.every(function(element, index) {
12
+      return element === b[index];
13
+    });
14
+  },
8
   hasValue : (a, b) => (a !== void 0) && (Array.isArray(a) ? a.length !==0 : true),
15
   hasValue : (a, b) => (a !== void 0) && (Array.isArray(a) ? a.length !==0 : true),
9
   isArray : (a, b) => Array.isArray(a),
16
   isArray : (a, b) => Array.isArray(a),
10
   hasProperties : (a, b) => {
17
   hasProperties : (a, b) => {

+ 73
- 47
test/react-native-testkit/lib/test-context.js View File

11
     timeout = val
11
     timeout = val
12
   }
12
   }
13
 
13
 
14
+  static config(config) {
15
+    return TestContext.describe.bind(config)
16
+  }
17
+
14
   /**
18
   /**
15
    * Calling this method will push a test case into task queue.
19
    * Calling this method will push a test case into task queue.
16
    * @param  {String}   desc Description of test case.
20
    * @param  {String}   desc Description of test case.
19
    * @return {void}
23
    * @return {void}
20
    */
24
    */
21
   static describe (desc:string, fn:Promise<any>) {
25
   static describe (desc:string, fn:Promise<any>) {
26
+    let { group, timeout, expand, run } = this || {}
22
 
27
 
23
-    tests.push({
28
+    let ctx = {
29
+      group : group || 'common',
24
       status : 'waiting',
30
       status : 'waiting',
31
+      run : run === false ? false : true,
25
       result : null,
32
       result : null,
26
       asserts : [],
33
       asserts : [],
27
-      timeout : 3000,
34
+      timeout : timeout || 3000,
28
       expired : false,
35
       expired : false,
29
       running : false,
36
       running : false,
30
       executed : false,
37
       executed : false,
31
-      desc, fn,
32
-    })
38
+      expand : expand || false,
39
+      desc,
40
+      fn,
41
+      sn : tests.length,
42
+      start : (i) => {
43
+        TestContext.startTest.bind(
44
+          tests[i],
45
+          TestContext.update.bind(TestContext, i),
46
+          TestContext.updateInternal.bind(TestContext, i)
47
+        )()
48
+      }
49
+    }
50
+    tests.push(ctx)
33
 
51
 
34
   }
52
   }
35
 
53
 
52
     let promise = Promise.resolve()
70
     let promise = Promise.resolve()
53
     // run test case sequently
71
     // run test case sequently
54
     for(let i in tests) {
72
     for(let i in tests) {
55
-      promise = promise.then(function(update, updateInternal, data) {
56
-        return new Promise((resolve, reject) => {
57
-
58
-          let expired = false
59
-          updateInternal({
60
-            running : true,
61
-          })
62
-
63
-          // set timeout timer
64
-          let tm = setTimeout(() => {
65
-            updateInternal({
66
-              expired : true,
67
-              executed : true,
68
-              running : false
69
-            })
70
-            resolve('ETIMEOUT')
71
-          }, this.timeout)
72
-
73
-          // run test body
74
-          new Promise((done) => {
75
-            this.fn.bind(this)(update, done)
76
-          })
77
-          .then((...res) => {
78
-            if(!expired) {
79
-              clearTimeout(tm)
80
-              updateInternal({
81
-                executed : true,
82
-                running : false
83
-              })
84
-              resolve(...res)
85
-            }
86
-          }).catch((err) => {
87
-            updateInternal({
88
-              executed : true,
89
-              running : false
90
-            })
91
-          })
92
-
93
-        })
73
+      if(tests[i].run === false) {
74
+        tests[i].status = 'skipped'
75
+        tests[i].executed = true
76
+        promise = Promise.resolve()
77
+        continue
94
       }
78
       }
95
-      .bind(
96
-        tests[i],
97
-        TestContext.update.bind(TestContext, i),
98
-        TestContext.updateInternal.bind(TestContext, i)
79
+      promise = promise.then(
80
+        TestContext.startTest.bind(
81
+          tests[i],
82
+          TestContext.update.bind(TestContext, i),
83
+          TestContext.updateInternal.bind(TestContext, i)
99
       ))
84
       ))
100
     }
85
     }
101
     return promise
86
     return promise
102
   }
87
   }
103
 
88
 
89
+  static startTest(update, updateInternal, data) {
90
+    return new Promise((resolve, reject) => {
91
+
92
+      let expired = false
93
+      updateInternal({
94
+        running : true,
95
+      })
96
+
97
+      // set timeout timer
98
+      let tm = setTimeout(() => {
99
+        updateInternal({
100
+          expired : true,
101
+          executed : true,
102
+          running : false
103
+        })
104
+        resolve('ETIMEOUT')
105
+      }, this.timeout)
106
+
107
+      // run test body
108
+      new Promise((done) => {
109
+        this.fn.bind(this)(update, done)
110
+      })
111
+      .then((...res) => {
112
+        if(!expired) {
113
+          clearTimeout(tm)
114
+          updateInternal({
115
+            executed : true,
116
+            running : false
117
+          })
118
+          resolve(...res)
119
+        }
120
+      }).catch((err) => {
121
+        updateInternal({
122
+          executed : true,
123
+          running : false
124
+        })
125
+      })
126
+
127
+    })
128
+  }
129
+
104
   /**
130
   /**
105
    * Update test task result of given index.
131
    * Update test task result of given index.
106
    * @param  {number} i       Index of test case to be updated.
132
    * @param  {number} i       Index of test case to be updated.

+ 6
- 1
test/test-0.1.x-0.4.x.js View File

10
   Dimensions,
10
   Dimensions,
11
   Image,
11
   Image,
12
 } from 'react-native';
12
 } from 'react-native';
13
-const { Assert, Comparer, Info, describe, prop } = RNTest
13
+const { Assert, Comparer, Info, prop } = RNTest
14
+const describe = RNTest.config({
15
+  group : '0.1.x - 0.4.x',
16
+  expand : false,
17
+  run : false
18
+})
14
 
19
 
15
 let { TEST_SERVER_URL, FILENAME, DROPBOX_TOKEN, styles, image } = prop()
20
 let { TEST_SERVER_URL, FILENAME, DROPBOX_TOKEN, styles, image } = prop()
16
 
21
 

+ 102
- 3
test/test-0.5.x.js View File

12
   Image,
12
   Image,
13
 } from 'react-native';
13
 } from 'react-native';
14
 
14
 
15
-const { Assert, Comparer, Info, describe, prop } = RNTest
15
+const { Assert, Comparer, Info, prop } = RNTest
16
+const describe = RNTest.config({
17
+  group : '0.5.x',
18
+  expand : false,
19
+})
16
 const { TEST_SERVER_URL, FILENAME, DROPBOX_TOKEN, styles } = prop()
20
 const { TEST_SERVER_URL, FILENAME, DROPBOX_TOKEN, styles } = prop()
17
 
21
 
18
 let prefix = ((Platform.OS === 'android') ? 'file://' : '')
22
 let prefix = ((Platform.OS === 'android') ? 'file://' : '')
60
 
64
 
61
 describe('Read cached file via file stream', (report, done) => {
65
 describe('Read cached file via file stream', (report, done) => {
62
   let data = 'data:image/png;base64, '
66
   let data = 'data:image/png;base64, '
63
-  let stream = RNFetchBlob.openReadStream(tmpFilePath, 'base64')
67
+  let stream = RNFetchBlob.readStream(tmpFilePath, 'base64')
64
   stream.onData((chunk) => {
68
   stream.onData((chunk) => {
65
     data += chunk
69
     data += chunk
66
   })
70
   })
81
 })
85
 })
82
 
86
 
83
 describe('File stream reader error should be able to handled', (report, done) => {
87
 describe('File stream reader error should be able to handled', (report, done) => {
84
-  let stream = RNFetchBlob.openReadStream('^_^ not exists', 'base64')
88
+  let stream = RNFetchBlob.readStream('^_^ not exists', 'base64')
85
   stream.onError((err) => {
89
   stream.onError((err) => {
86
     report(<Info key="error message">
90
     report(<Info key="error message">
87
       <Text>
91
       <Text>
94
 })
98
 })
95
 
99
 
96
 let localFile = null
100
 let localFile = null
101
+let sysDirs = null
97
 
102
 
98
 describe('Upload from file storage', (report, done) => {
103
 describe('Upload from file storage', (report, done) => {
99
   let filename = ''
104
   let filename = ''
100
   let filepath = ''
105
   let filepath = ''
101
   RNFetchBlob.getSystemDirs().then((dirs) => {
106
   RNFetchBlob.getSystemDirs().then((dirs) => {
107
+    sysDirs = dirs
102
     filename = Platform.OS + '0.5.0-' + Date.now() + '-from-storage.png'
108
     filename = Platform.OS + '0.5.0-' + Date.now() + '-from-storage.png'
103
     filepath = dirs.DocumentDir + '/' + filename
109
     filepath = dirs.DocumentDir + '/' + filename
104
     return RNFetchBlob.config({ path : filepath })
110
     return RNFetchBlob.config({ path : filepath })
148
       </Info>)
154
       </Info>)
149
       done()
155
       done()
150
     })
156
     })
157
+})
158
+
159
+describe('Session create mechanism test', (report, done) => {
160
+  let sessionName = 'foo-' + Date.now()
161
+  testSessionName = sessionName
162
+  let p1 = RNFetchBlob.config({
163
+      session : sessionName,
164
+      fileCache : true
165
+    })
166
+    .fetch('GET', `${TEST_SERVER_URL}/public/github2.jpg`)
167
+  let p2 = RNFetchBlob.config({
168
+      fileCache : true
169
+    })
170
+    .fetch('GET', `${TEST_SERVER_URL}/public/github.png`)
171
+  let p3 = RNFetchBlob.config({
172
+      path : sysDirs.DocumentDir + '/session-test.png'
173
+    })
174
+    .fetch('GET', `${TEST_SERVER_URL}/public/github.png`)
175
+
176
+  let promises = [p1, p2, p3]
177
+  Promise.all(promises).then((resp) => {
178
+    let session = RNFetchBlob.session(sessionName).add(resp[1].path())
179
+    resp[2].session(sessionName)
180
+    let actual = session.list()
181
+    let expect = resp.map((p) => {
182
+      return p.path()
183
+    })
184
+    report(
185
+      <Assert key="check if session state correct"
186
+        expect={expect}
187
+        comparer={Comparer.equalToArray}
188
+        actual={actual} />)
189
+    done()
190
+  })
191
+
192
+})
193
+
194
+describe('Session API CRUD test', (report, done) => {
195
+
196
+  let sessionName = 'test-session-' + Date.now()
197
+  let baseDir = sysDirs.DocumentDir + '/' + sessionName
198
+  RNFetchBlob.mkdir(sysDirs.DocumentDir + '/' + sessionName).then(() => {
199
+    let promises = [0,1,2,3,4,5,6,7,8,9].map((p) => {
200
+      return RNFetchBlob.config({
201
+          session : sessionName,
202
+          path : baseDir + '/testfile' + p
203
+        })
204
+        .fetch('GET', `${TEST_SERVER_URL}/public/github2.jpg`)
205
+    })
206
+    return Promise.all(promises)
207
+  })
208
+  .then((resps) => {
209
+    let s = RNFetchBlob.session(sessionName)
210
+    report(
211
+      <Assert
212
+        key="list() length validation"
213
+        expect={10}
214
+        actual={s.list().length}/>)
215
+    let modified = [
216
+      s.list()[2],
217
+      s.list()[3],
218
+      s.list()[4],
219
+      s.list()[5],
220
+      s.list()[6],
221
+      s.list()[7],
222
+      s.list()[8],
223
+      s.list()[9],
224
+    ]
225
+    let expect = [s.list()[0], s.list()[1]]
226
+    s.remove(s.list()[0])
227
+    s.remove(s.list()[0])
228
+    report(
229
+      <Assert
230
+        key="remove() should work correctly"
231
+        expect={modified}
232
+        comparer={Comparer.equalToArray}
233
+        actual={s.list()}/>)
234
+
235
+    s.dispose().then(() => {
236
+      RNFetchBlob.ls(baseDir).then((lsRes) => {
237
+        report(
238
+          <Assert
239
+            key="dispose() should work correctly"
240
+            expect={expect}
241
+            comparer={Comparer.equalToArray}
242
+            actual={lsRes.map((p) => {
243
+              return baseDir + '/' + p
244
+            })}/>)
245
+      })
246
+      done()
247
+    })
248
+
249
+  })
151
 
250
 
152
 })
251
 })

+ 2
- 2
test/test-init.js View File

18
 // test environment variables
18
 // test environment variables
19
 
19
 
20
 prop('FILENAME', `${Platform.OS}-0.5.0-${Date.now()}.png`)
20
 prop('FILENAME', `${Platform.OS}-0.5.0-${Date.now()}.png`)
21
-prop('TEST_SERVER_URL', 'http://192.168.17.193:8123')
21
+prop('TEST_SERVER_URL', 'http://192.168.0.14:8123')
22
 prop('DROPBOX_TOKEN', 'fsXcpmKPrHgAAAAAAAAAoXZhcXYWdgLpQMan6Tb_bzJ237DXhgQSev12hA-gUXt4')
22
 prop('DROPBOX_TOKEN', 'fsXcpmKPrHgAAAAAAAAAoXZhcXYWdgLpQMan6Tb_bzJ237DXhgQSev12hA-gUXt4')
23
 prop('styles', {
23
 prop('styles', {
24
   image : {
24
   image : {
51
     })
51
     })
52
 })
52
 })
53
 
53
 
54
-// require('./test-0.1.x-0.4.x')
54
+require('./test-0.1.x-0.4.x')
55
 require('./test-0.5.x')
55
 require('./test-0.5.x')