Search code examples
javascriptnode.jstwittertwitter-streaming-apinock

How do I return mock data from requests to the Twitter Streaming API in Node


I have a Node application that connects to the Twitter REST and streaming APIs. In order to test code that makes requests to the REST API, I can use Nock to intercept the HTTP request and return mock data like so:

var nock = require('nock')

var mockData = [...]

nock('https://api.twitter.com/1.1')
.get('/search/tweets.json')
.reply(200, mockData)

My application also connects to the streaming API endpoint statuses/filter and performs some analysis on tweets received via the streaming API. In Nock's README it states that you can pass a function to .query() that returns a stream, however I haven't been able to get this to work.

How would I return mock data from requests to this endpoint using Nock (or another library if necessary)? I'd ideally like to be able to send tweets to the stream in my tests whenever I need to, for example:

it('should correctly process tweets coming in on the streaming API', () => {
    var mockTweet = {...}

    sendMockTweetToStream(mockTweet)

    ...verify that the mock tweet was received and processed

})

Solution

  • I've found a way to do this in my tests without mocking the streaming API.

    I'm using the NPM Twitter package to access the Twitter streaming API like so:

    var client = new Twitter({
      consumer_key: twitterConsumerKey,
      consumer_secret: twitterConsumerSecret,
      access_token_key: twitterAccessTokenKey,
      access_token_secret: twitterAccessTokenSecret
    })
    
    stream = client.stream('statuses/filter', {track: 'something'})
    
    stream.on('data', event => {
      // Do some processing of incoming tweets here
    })
    

    Instead of mocking the streaming API, I mocked the client object using my own stream with rewire, and set up a function to allow me to send it mock tweets whenever I want.

    const rewire = require('rewire')
    const stream = rewire('stream')
    const moduleToTest = require('somemodule')
    
    const mockStream = new stream.Readable()
    mockStream._read = () => {}
    mockStream.destroy = () => {}
    
    // Send a Tweet event to the mock stream
    function writeTweetToStream (text) {
      mockStream.emit('data', {text: text})
    }
    
    describe('Module that uses the Twitter Streaming API', () => {
      beforeAll(() => {
        // client.stream should return our mock stream
        moduleToTest.__set__('client', {stream: () => { return mockStream }})
      })
    
      it('should process incoming tweets', () => {
        writeTweetToStream('This is a tweet #somehashtag')
    
        // Assert that the tweet was received and processed
      })
    })