huridocs/uwazi

View on GitHub
app/api/services/twitterintegration/specs/TwitterIntegration.spec.ts

Summary

Maintainability
B
6 hrs
Test Coverage
import { testingDB } from 'api/utils/testing_db';
import * as filesApi from 'api/files/filesystem';
import { storage, files } from 'api/files';
import {
  TweetParamsType,
  TwitterIntegration,
} from 'api/services/twitterintegration/TwitterIntegration';
import {
  fixturesOneTenant,
  fixturesOtherTenant,
  fixturesTenantWithoutTwitter,
} from 'api/services/twitterintegration/specs/fixtures';
import EntitiesModel from 'api/entities/entitiesModel';
import templates from 'api/templates/templates';
import { testingTenants } from 'api/utils/testingTenants';
import { testingEnvironment } from 'api/utils/testingEnvironment';
import { tenants } from 'api/tenants';
import fetchMock from 'fetch-mock';

jest.mock('api/services/tasksmanager/TaskManager.ts');
jest.mock('api/socketio/setupSockets');

const ONE_TWEET_PARAMS: TweetParamsType = {
  title: 'tweet title',
  text: 'tweet text',
  source: 'url',
  user: { display_name: 'user', url: 'user_url' },
  created_at: 1645747200,
  hashtags: ['#other_hashtag_example', '#hashtag_example'],
  images_urls: [],
};

const tenantName = 'tenant_twitter_integration';

describe('TwitterIntegration', () => {
  let twitterIntegration: TwitterIntegration;

  beforeEach(async () => {
    twitterIntegration = new TwitterIntegration();

    const folders = {
      uploadedDocuments: `${__dirname}/uploads`,
      attachments: `${__dirname}/uploads`,
      customUploads: `${__dirname}/uploads`,
      activityLogs: `${__dirname}/uploads`,
    };

    const tenant1 = {
      name: tenantName,
      dbName: tenantName,
      indexName: tenantName,
      ...folders,
    };

    tenants.tenants = { tenant_twitter_integration: tenant1 };

    jest.resetAllMocks();
  });

  afterAll(async () => {
    await testingEnvironment.tearDown();
  });

  it('should do nothing with tenant without the twitter setup', async () => {
    await testingEnvironment.setUp(fixturesTenantWithoutTwitter);
    testingTenants.changeCurrentTenant({
      name: tenantName,
    });
    await twitterIntegration.addTweetsRequestsToQueue();

    expect(twitterIntegration.twitterTaskManager.startTask).not.toHaveBeenCalled();
  });

  it('should send a twitter requests', async () => {
    await testingDB.setupFixturesAndContext(fixturesOneTenant, tenantName);

    await twitterIntegration.addTweetsRequestsToQueue();

    expect(twitterIntegration.twitterTaskManager.startTask).toHaveBeenCalledWith({
      params: { query: '#hashtag-example', tweets_languages: ['en'] },
      tenant: tenantName,
      task: 'get-hashtag',
    });
  });

  it('should create templates if they do not exist', async () => {
    await testingDB.setupFixturesAndContext(fixturesOneTenant, tenantName);

    await twitterIntegration.processResults({
      tenant: tenantName,
      task: 'get-hashtag',
      params: ONE_TWEET_PARAMS,
    });

    const [hashtagTemplate] = await templates.get({ name: 'Hashtags' });
    const [tweetsTemplate] = await templates.get({ name: 'Tweets' });
    expect(hashtagTemplate.name).toBe('Hashtags');
    expect(tweetsTemplate.name).toBe('Tweets');
  });

  it('should create other templates if they do not exist', async () => {
    await testingDB.setupFixturesAndContext(fixturesOtherTenant, tenantName);

    await twitterIntegration.processResults({
      tenant: tenantName,
      task: 'get-hashtag',
      params: ONE_TWEET_PARAMS,
    });

    const [hashtagTemplate] = await templates.get({ name: 'OtherHashtags' });
    const [tweetsTemplate] = await templates.get({ name: 'OtherTweets' });
    expect(hashtagTemplate.name).toBe('OtherHashtags');
    expect(tweetsTemplate.name).toBe('OtherTweets');
  });

  it('should store one tweet', async () => {
    await testingDB.setupFixturesAndContext(fixturesOneTenant, tenantName);

    await twitterIntegration.processResults({
      tenant: tenantName,
      task: 'get-hashtag',
      params: ONE_TWEET_PARAMS,
    });

    const tweetsEntities = await EntitiesModel.getUnrestricted({ title: 'tweet title' });

    const [tweetEntity] = tweetsEntities;
    expect(tweetsEntities.length).toBe(1);
    expect(tweetEntity).toMatchObject({
      title: 'tweet title',
      metadata: {
        tweet_text: [{ value: 'tweet text' }],
        tweet_source: [{ value: { label: 'link', url: 'url' } }],
        tweet_author: [{ value: { label: 'user', url: 'user_url' } }],
        tweet_date: [{ value: 1645747200 }],
      },
    });
  });

  it('should store the hashtags', async () => {
    await testingDB.setupFixturesAndContext(fixturesOneTenant, tenantName);

    await twitterIntegration.processResults({
      tenant: tenantName,
      task: 'get-hashtag',
      params: ONE_TWEET_PARAMS,
    });

    await twitterIntegration.processResults({
      tenant: tenantName,
      task: 'get-hashtag',
      params: ONE_TWEET_PARAMS,
    });

    const hashtagsEntities = await EntitiesModel.getUnrestricted({
      $or: [{ title: '#other_hashtag_example' }, { title: '#hashtag_example' }],
    });
    const tweetsEntities = await EntitiesModel.getUnrestricted({
      $nor: [{ title: '#other_hashtag_example' }, { title: '#hashtag_example' }],
    });

    const tweetEntity = tweetsEntities[0];
    expect(hashtagsEntities.length).toBe(2);
    expect(hashtagsEntities.map(x => x.title)).toEqual([
      '#other_hashtag_example',
      '#hashtag_example',
    ]);
    expect(tweetEntity.metadata?.tweet_hashtags).toMatchObject(
      hashtagsEntities.map(x => ({
        value: x.sharedId,
      }))
    );
  });

  it('should download and replace the images in the twitter text', async () => {
    const storeFileSpy = jest.spyOn(storage, 'storeFile').mockResolvedValue();
    jest.spyOn(filesApi, 'generateFileName').mockReturnValue('generatedUwaziFilename');

    fetchMock.mock('https://image.is', {
      body: 'resultFileContent',
      status: 200,
      headers: { 'Content-Type': 'some/mimetype' },
    });

    await testingDB.setupFixturesAndContext(fixturesOneTenant, tenantName);

    const imageParams = {
      ...ONE_TWEET_PARAMS,
      text: 'tweet text ![image](https://image.is)',
      images_urls: ['https://image.is'],
    };

    await twitterIntegration.processResults({
      tenant: tenantName,
      task: 'get-hashtag',
      params: imageParams,
    });

    const fileDocuments = await files.get();
    const tweetsEntities = await EntitiesModel.getUnrestricted({ title: ONE_TWEET_PARAMS.title });

    expect(fileDocuments.length).toBe(1);
    expect(tweetsEntities.length).toBe(1);
    expect(fetchMock.lastUrl()).toBe('https://image.is/');
    expect(fileDocuments[0]).toMatchObject({
      entity: tweetsEntities[0].sharedId,
      filename: 'generatedUwaziFilename',
      originalname: 'image.is',
      type: 'attachment',
    });
    expect(storeFileSpy).toHaveBeenCalledWith(
      'generatedUwaziFilename',
      expect.anything(),
      expect.anything()
    );
    expect(tweetsEntities[0]).toMatchObject({
      metadata: {
        tweet_text: [
          {
            value: 'tweet text ![image](/api/files/generatedUwaziFilename)',
          },
        ],
      },
    });
  });
});