1 | var assert = require('assert')
|
2 | , Twit = require('../lib/twitter')
|
3 | , config1 = require('../config1')
|
4 | , util = require('util')
|
5 | , async = require('async')
|
6 |
|
7 | describe('REST API', function () {
|
8 | var twit = null
|
9 |
|
10 | before(function () {
|
11 | twit = new Twit(config1);
|
12 | })
|
13 |
|
14 | it('GET `account/verify_credentials`', function (done) {
|
15 | twit.get('account/verify_credentials', function (err, reply, response) {
|
16 | checkReply(err, reply)
|
17 | assert.notEqual(reply.followers_count, undefined)
|
18 | assert.notEqual(reply.friends_count, undefined)
|
19 | assert.ok(reply.id_str)
|
20 |
|
21 | checkResponse(response)
|
22 |
|
23 | assert(response.headers['x-rate-limit-limit'])
|
24 |
|
25 | done()
|
26 | })
|
27 | })
|
28 |
|
29 | it('POST `account/update_profile`', function (done) {
|
30 | twit.post('account/update_profile', function (err, reply, response) {
|
31 | checkReply(err, reply)
|
32 | console.log('\nscreen name:', reply.screen_name)
|
33 | checkResponse(response)
|
34 | done()
|
35 | })
|
36 | })
|
37 |
|
38 | var tweetId = null
|
39 | , text = null
|
40 |
|
41 | it('POST `statuses/update`', function (done) {
|
42 | var params = { status: '@tolga_tezel tweeting using github.com/ttezel/twit' }
|
43 | twit.post('statuses/update', params, function (err, reply, response) {
|
44 | checkReply(err, reply)
|
45 |
|
46 | console.log('\ntweeted:', reply.text)
|
47 | console.log('tweeted on:', reply.created_at)
|
48 |
|
49 | tweetId = reply.id_str
|
50 | text = reply.text
|
51 |
|
52 | checkResponse(response)
|
53 |
|
54 | done()
|
55 | })
|
56 | })
|
57 |
|
58 | it('POST `statuses/destroy:id`', function (done) {
|
59 | var destroyRoute = 'statuses/destroy/'+tweetId
|
60 |
|
61 | twit.post(destroyRoute, function (err, reply, response) {
|
62 | checkReply(err, reply)
|
63 | checkTweet(reply)
|
64 | assert.equal(reply.text, text)
|
65 |
|
66 | checkResponse(response)
|
67 |
|
68 | done()
|
69 | })
|
70 | })
|
71 |
|
72 | it('POST `statuses/update` with characters requiring escaping', function (done) {
|
73 | var params = { status: '@tolga_tezel tweeting using github.com/ttezel/twit :) !' }
|
74 |
|
75 | twit.post('statuses/update', params, function (err, reply, response) {
|
76 | checkReply(err, reply)
|
77 |
|
78 | console.log('\ntweeted:', reply.text)
|
79 | console.log('tweeted on:', reply.created_at)
|
80 |
|
81 | checkResponse(response)
|
82 |
|
83 | var text = reply.text
|
84 |
|
85 | assert(reply.id_str)
|
86 |
|
87 | console.log('id_str', reply.id_str)
|
88 |
|
89 | twit.post('statuses/destroy/:id', { id: reply.id_str }, function (err, reply, response) {
|
90 | checkReply(err, reply)
|
91 | checkTweet(reply)
|
92 | assert.equal(reply.text, text)
|
93 |
|
94 | checkResponse(response)
|
95 |
|
96 | done()
|
97 | })
|
98 | })
|
99 | })
|
100 |
|
101 | it('POST `statuses/update` with \'Hi!!\' works', function (done) {
|
102 | var params = { status: 'Hi!!' }
|
103 |
|
104 | twit.post('statuses/update', params, function (err, reply, response) {
|
105 | checkReply(err, reply)
|
106 |
|
107 | console.log('\ntweeted:', reply.text)
|
108 | console.log('tweeted on:', reply.created_at)
|
109 |
|
110 | checkResponse(response)
|
111 |
|
112 | var text = reply.text
|
113 |
|
114 | var destroyRoute = 'statuses/destroy/'+reply.id_str
|
115 |
|
116 | twit.post(destroyRoute, function (err, reply, response) {
|
117 | checkReply(err, reply)
|
118 | checkTweet(reply)
|
119 | assert.equal(reply.text, text)
|
120 |
|
121 | checkResponse(response)
|
122 |
|
123 | done()
|
124 | })
|
125 | })
|
126 | })
|
127 |
|
128 | it('GET `statuses/home_timeline`', function (done) {
|
129 | twit.get('statuses/home_timeline', function (err, reply, response) {
|
130 | checkReply(err, reply)
|
131 | checkTweet(reply[0])
|
132 |
|
133 | checkResponse(response)
|
134 |
|
135 | done()
|
136 | })
|
137 | })
|
138 |
|
139 | it('GET `statuses/mentions_timeline`', function (done) {
|
140 | twit.get('statuses/mentions_timeline', function (err, reply, response) {
|
141 | checkReply(err, reply)
|
142 | checkTweet(reply[0])
|
143 | done()
|
144 | })
|
145 | })
|
146 |
|
147 | it('GET `statuses/user_timeline`', function (done) {
|
148 | var params = {
|
149 | screen_name: 'tolga_tezel'
|
150 | }
|
151 |
|
152 | twit.get('statuses/user_timeline', params, function (err, reply, response) {
|
153 | checkReply(err, reply)
|
154 | checkTweet(reply[0])
|
155 |
|
156 | checkResponse(response)
|
157 |
|
158 | done()
|
159 | })
|
160 | })
|
161 |
|
162 | it('GET `search/tweets` { q: "a", since_id: 12345 }', function (done) {
|
163 | var params = { q: 'a', since_id: 12345 }
|
164 | twit.get('search/tweets', params, function (err, reply, response) {
|
165 | checkReply(err, reply)
|
166 | assert.ok(reply.statuses)
|
167 | checkTweet(reply.statuses[0])
|
168 |
|
169 | checkResponse(response)
|
170 |
|
171 | done()
|
172 | })
|
173 | })
|
174 |
|
175 | it('GET `search/tweets` { q: "fun since:2011-11-11" }', function (done) {
|
176 | var params = { q: 'fun since:2011-11-11', count: 100 }
|
177 | twit.get('search/tweets', params, function (err, reply, response) {
|
178 | checkReply(err, reply)
|
179 | assert.ok(reply.statuses)
|
180 | checkTweet(reply.statuses[0])
|
181 |
|
182 | console.log('\nnumber of fun statuses:', reply.statuses.length)
|
183 |
|
184 | checkResponse(response)
|
185 |
|
186 | done()
|
187 | })
|
188 | })
|
189 |
|
190 | it('GET `search/tweets`, using `q` array', function (done) {
|
191 | var params = {
|
192 | q: [ 'banana', 'mango', 'peach' ]
|
193 | }
|
194 |
|
195 | twit.get('search/tweets', params, function (err, reply, response) {
|
196 | checkReply(err, reply)
|
197 | assert.ok(reply.statuses)
|
198 | checkTweet(reply.statuses[0])
|
199 |
|
200 | checkResponse(response)
|
201 |
|
202 | done()
|
203 | })
|
204 | })
|
205 |
|
206 | it('GET `search/tweets` with count set to 100', function (done) {
|
207 | var params = {
|
208 | q: 'happy',
|
209 | count: 100
|
210 | }
|
211 |
|
212 | twit.get('search/tweets', params, function (err, reply, res) {
|
213 | checkReply(err, reply)
|
214 | console.log('\nnumber of tweets from search:', reply.statuses.length)
|
215 |
|
216 |
|
217 | assert(reply.statuses.length > 95)
|
218 |
|
219 | done()
|
220 | })
|
221 | })
|
222 |
|
223 | it('GET `search/tweets` with geocode', function (done) {
|
224 | var params = {
|
225 | q: 'apple', geocode: [ '37.781157', '-122.398720', '1mi' ]
|
226 | }
|
227 |
|
228 | twit.get('search/tweets', params, function (err, reply) {
|
229 | checkReply(err, reply)
|
230 |
|
231 | done()
|
232 | })
|
233 | })
|
234 |
|
235 | it('GET `direct_messages`', function (done) {
|
236 | twit.get('direct_messages', function (err, reply, response) {
|
237 | checkReply(err, reply)
|
238 | assert.ok(Array.isArray(reply))
|
239 | exports.checkDm(reply[0])
|
240 |
|
241 | checkResponse(response)
|
242 |
|
243 | done()
|
244 | })
|
245 | })
|
246 |
|
247 | it('GET `followers/ids`', function (done) {
|
248 | twit.get('followers/ids', function (err, reply, response) {
|
249 | checkReply(err, reply)
|
250 | assert.ok(Array.isArray(reply.ids))
|
251 |
|
252 | checkResponse(response)
|
253 |
|
254 | done()
|
255 | })
|
256 | })
|
257 |
|
258 | it('GET `followers/ids` of screen_name tolga_tezel', function (done) {
|
259 | twit.get('followers/ids', { screen_name: 'tolga_tezel' }, function (err, reply, response) {
|
260 | checkReply(err, reply)
|
261 | assert.ok(Array.isArray(reply.ids))
|
262 |
|
263 | checkResponse(response)
|
264 |
|
265 | done()
|
266 | })
|
267 | })
|
268 |
|
269 | it('POST `statuses/retweet`', function (done) {
|
270 |
|
271 | twit.get('search/tweets', { q: 'apple' }, function (err, reply, response) {
|
272 | checkReply(err, reply)
|
273 | assert.ok(reply.statuses)
|
274 |
|
275 | var tweet = reply.statuses[0]
|
276 | checkTweet(tweet)
|
277 |
|
278 | var tweetId = tweet.id_str
|
279 | assert(tweetId)
|
280 |
|
281 | twit.post('statuses/retweet/'+tweetId, function (err, reply, response) {
|
282 | checkReply(err, reply)
|
283 |
|
284 | var retweetId = reply.id_str
|
285 | assert(retweetId)
|
286 |
|
287 | twit.post('statuses/destroy/'+retweetId, function (err, reply, response) {
|
288 | checkReply(err, reply)
|
289 |
|
290 | done()
|
291 | })
|
292 | })
|
293 | })
|
294 | })
|
295 |
|
296 |
|
297 | it('POST `statuses/retweet/:id` without `id` in params returns error', function (done) {
|
298 | twit.post('statuses/retweet/:id', function (err, reply, response) {
|
299 | assert(err)
|
300 | assert.equal(err.message, 'Twit: Params object is missing a required parameter for this request: `id`')
|
301 | done()
|
302 | })
|
303 | })
|
304 |
|
305 |
|
306 | it('POST `statuses/retweet/:id`', function (done) {
|
307 |
|
308 | twit.get('search/tweets', { q: 'banana' }, function (err, reply, response) {
|
309 | checkReply(err, reply)
|
310 | assert.ok(reply.statuses)
|
311 |
|
312 | var tweet = reply.statuses[0]
|
313 | checkTweet(tweet)
|
314 |
|
315 | var tweetId = tweet.id_str
|
316 | assert(tweetId)
|
317 |
|
318 | twit.post('statuses/retweet/:id', { id: tweetId }, function (err, reply) {
|
319 | checkReply(err, reply)
|
320 |
|
321 | var retweetId = reply.id_str
|
322 | assert(retweetId)
|
323 |
|
324 | twit.post('statuses/destroy/:id', { id: retweetId }, function (err, reply, response) {
|
325 | checkReply(err, reply)
|
326 |
|
327 | done()
|
328 | })
|
329 | })
|
330 | })
|
331 | })
|
332 |
|
333 |
|
334 | it('GET `users/suggestions/:slug`', function (done) {
|
335 | twit.get('users/suggestions/:slug', { slug: 'funny' }, function (err, reply, res) {
|
336 | checkReply(err, reply)
|
337 | assert.equal(reply.slug, 'funny')
|
338 | done()
|
339 | })
|
340 | })
|
341 |
|
342 |
|
343 | it('GET `users/suggestions/:slug/members`', function (done) {
|
344 | twit.get('users/suggestions/:slug/members', { slug: 'funny' }, function (err, reply, res) {
|
345 | checkReply(err, reply)
|
346 |
|
347 | assert(reply[0].id_str)
|
348 | assert(reply[0].screen_name)
|
349 |
|
350 | done()
|
351 | })
|
352 | })
|
353 |
|
354 |
|
355 | it('GET `geo/id/:place_id`', function (done) {
|
356 | var placeId = 'df51dec6f4ee2b2c'
|
357 |
|
358 | twit.get('geo/id/:place_id', { place_id: placeId }, function (err, reply, res) {
|
359 | checkReply(err, reply)
|
360 |
|
361 | assert(reply.country)
|
362 | assert(reply.bounding_box)
|
363 | assert.equal(reply.id, placeId)
|
364 |
|
365 | done()
|
366 | })
|
367 | })
|
368 |
|
369 | it('POST `direct_messages/new`', function (done) {
|
370 | var dmId
|
371 |
|
372 | async.series({
|
373 | postDm: function (next) {
|
374 |
|
375 | var dmParams = {
|
376 | screen_name: 'tolga_tezel',
|
377 | text: 'hey this is a direct message from twit! :)'
|
378 | }
|
379 |
|
380 | twit.post('direct_messages/new', dmParams, function (err, reply) {
|
381 | assert(!err, err)
|
382 | assert(reply)
|
383 |
|
384 | dmId = reply.id_str
|
385 |
|
386 | exports.checkDm(reply)
|
387 |
|
388 | assert.equal(reply.text, dmParams.text)
|
389 | assert(dmId)
|
390 |
|
391 | return next()
|
392 | })
|
393 | },
|
394 | deleteDm: function (next) {
|
395 | twit.post('direct_messages/destroy', { id: dmId }, function (err, reply) {
|
396 | assert(!err, err)
|
397 | exports.checkDm(reply)
|
398 | assert.equal(reply.id, dmId)
|
399 |
|
400 | return next()
|
401 | })
|
402 | }
|
403 | }, done)
|
404 | })
|
405 |
|
406 | describe('error handling', function () {
|
407 | describe('handling errors from the twitter api', function () {
|
408 | it('should callback with an Error object with all the info and a response object', function (done) {
|
409 | var twit = new Twit({
|
410 | consumer_key: 'a',
|
411 | consumer_secret: 'b',
|
412 | access_token: 'c',
|
413 | access_token_secret: 'd'
|
414 | })
|
415 | twit.get('account/verify_credentials', function (err, reply, res) {
|
416 | assert(err instanceof Error)
|
417 | assert(err.statusCode === 401)
|
418 | assert(err.code > 0)
|
419 | assert(err.message.match(/token/))
|
420 | assert(err.twitterReply)
|
421 | assert(err.allErrors)
|
422 | assert(!reply)
|
423 | checkResponse(res);
|
424 | done()
|
425 | })
|
426 | })
|
427 | })
|
428 | describe('handling other errors', function () {
|
429 | it('should just forward them', function (done) {
|
430 | var twit = new Twit(config1);
|
431 |
|
432 | var fakeError = new Error('derp')
|
433 |
|
434 |
|
435 | var OARequest = require('../lib/oarequest')
|
436 | var orig = OARequest.prototype.makeRequest
|
437 | OARequest.prototype.makeRequest = function (cb) {
|
438 | cb(fakeError);
|
439 | }
|
440 |
|
441 | twit.get('account/verify_credentials', function (err, reply, res) {
|
442 | assert(err === fakeError)
|
443 |
|
444 |
|
445 | OARequest.prototype.makeRequest = orig
|
446 |
|
447 | done()
|
448 | })
|
449 | })
|
450 | })
|
451 | })
|
452 |
|
453 | })
|
454 |
|
455 |
|
456 |
|
457 |
|
458 |
|
459 |
|
460 |
|
461 | function checkReply (err, reply) {
|
462 | assert.equal(err, null, 'reply err:'+util.inspect(err, true, 10, true))
|
463 | assert.equal(typeof reply, 'object')
|
464 | }
|
465 |
|
466 |
|
467 |
|
468 |
|
469 |
|
470 | function checkResponse (response) {
|
471 | assert(response)
|
472 | assert(response.headers)
|
473 | }
|
474 |
|
475 |
|
476 |
|
477 |
|
478 |
|
479 |
|
480 | var checkTweet = exports.checkTweet = function (tweet) {
|
481 | assert.ok(tweet)
|
482 | assert.equal('string', typeof tweet.id_str, 'id_str wasnt string:'+tweet.id_str)
|
483 | assert.equal('string', typeof tweet.text)
|
484 |
|
485 | assert.ok(tweet.user)
|
486 | assert.equal('string', typeof tweet.user.id_str)
|
487 | assert.equal('string', typeof tweet.user.screen_name)
|
488 | }
|
489 |
|
490 |
|
491 |
|
492 |
|
493 |
|
494 |
|
495 | exports.checkDm = function checkDm (dm) {
|
496 | assert.ok(dm)
|
497 | assert.equal('string', typeof dm.id_str)
|
498 | assert.equal('string', typeof dm.text)
|
499 |
|
500 | var recipient = dm.recipient
|
501 |
|
502 | assert.ok(recipient)
|
503 | assert.equal('string', typeof recipient.id_str)
|
504 | assert.equal('string', typeof recipient.screen_name)
|
505 |
|
506 | var sender = dm.sender
|
507 |
|
508 | assert.ok(sender)
|
509 | assert.equal('string', typeof sender.id_str)
|
510 | assert.equal('string', typeof sender.screen_name)
|
511 |
|
512 | assert.equal('string', typeof dm.text)
|
513 | }
|
514 |
|
515 | exports.assertTweetHasText = function (tweet, text) {
|
516 | assert(tweet.text.toLowerCase().indexOf(text) !== -1, 'expected to find '+text+' in text: '+tweet.text);
|
517 | }
|