Skip to content

Commit

Permalink
test: cover part of helpers (#92)
Browse files Browse the repository at this point in the history
  • Loading branch information
louisgrasset committed Oct 23, 2023
1 parent 279deb3 commit 015699a
Show file tree
Hide file tree
Showing 24 changed files with 357 additions and 15 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ dist/
.DS_Store
.env*
!.env.example
coverage/

# Temporary files
cache*.json
Expand Down
3 changes: 3 additions & 0 deletions meta/testing/jest.config.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ module.exports = {
transform: {
"^.+\\.ts?$": ["ts-jest", {
useESM: true,
}],
"^.+\\.js?$": ["ts-jest", {
useESM: true,
}]
},
verbose: false,
Expand Down
Binary file added src/helpers/medias/__tests__/files/image-gif.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/helpers/medias/__tests__/files/image-jpeg.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/helpers/medias/__tests__/files/image-jpg.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/helpers/medias/__tests__/files/image-png.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/helpers/medias/__tests__/files/image-webp.webp
Binary file not shown.
Binary file added src/helpers/medias/__tests__/files/video-mp4.mp4
Binary file not shown.
24 changes: 24 additions & 0 deletions src/helpers/medias/__tests__/helpers/make-blob-from-file.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { readFileSync } from "fs";
import { resolve } from "path";

export const makeBlobFromFile = async (
fileName: string,
mimeType: string,
): Promise<Blob> => {
const file = readFileSync(resolve(__dirname, `../files/${fileName}`));
return new Blob([file], { type: mimeType });
};

const makeUint8ArrayFromBlob = async (blob: Blob): Promise<Uint8Array> => {
const arrayBuffer = await blob.arrayBuffer();
const buffer = Buffer.from(arrayBuffer);
return new Uint8Array(buffer);
};

export const makeUint8ArrayFromFile = async (
fileName: string,
mimeType: string,
): Promise<Uint8Array> => {
const blob = await makeBlobFromFile(fileName, mimeType);
return await makeUint8ArrayFromBlob(blob);
};
51 changes: 51 additions & 0 deletions src/helpers/medias/__tests__/parse-blob-for-bluesky.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { parseBlobForBluesky } from "../parse-blob-for-bluesky.js";
import {
makeBlobFromFile,
makeUint8ArrayFromFile,
} from "./helpers/make-blob-from-file.js";

let imageBlob: Blob;
let bskyBlobData: Uint8Array;
const initBlobsForMime = async (mimeType: string) => {
const [type, extension] = mimeType.split("/");
const fileName = `${type}-${extension}.${extension}`;

bskyBlobData = await makeUint8ArrayFromFile(fileName, mimeType);
imageBlob = await makeBlobFromFile(fileName, mimeType);
};

describe("parseBlobForBluesky", () => {
describe("when the mime type is not supported", () => {
it.each`
mimeType
${"video/mp4"}
${"image/webp"}
`("should reject for $mimeType", async ({ mimeType }) => {
await initBlobsForMime(mimeType);

await expect(parseBlobForBluesky(imageBlob)).rejects.toContain(
"not supported",
);
});
});

describe("when the mime type is supported", () => {
it.each`
mimeType
${"image/jpeg"}
${"image/jpg"}
${"image/png"}
`(
"should resolve bluesky compatible blob for $mimeType",
async ({ mimeType }) => {
await initBlobsForMime(mimeType);

const result = await parseBlobForBluesky(imageBlob);
expect(result).toStrictEqual({
blobData: bskyBlobData,
mimeType,
});
},
);
});
});
2 changes: 1 addition & 1 deletion src/helpers/medias/parse-blob-for-bluesky.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ interface BlueskyBlob {
*/
export const parseBlobForBluesky = async (blob: Blob): Promise<BlueskyBlob> => {
return new Promise<BlueskyBlob>((resolve, reject) => {
const allowedMimeTypes = ["image/jpeg", "image/png"];
const allowedMimeTypes = ["image/jpeg", "image/jpg", "image/png"];
const mimeType = blob.type;

blob.arrayBuffer().then((ab) => {
Expand Down
10 changes: 10 additions & 0 deletions src/helpers/post/__tests__/get-post-excerpt.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { getPostExcerpt } from "../get-post-excerpt.js";

describe("getPostExcerpt", () => {
it("should return the 25 first characters and remove break lines", () => {
const result = getPostExcerpt(
"This is a test from\n the Potato Inc. tech lead",
);
expect(result).toBe("« This is a test from the P... »");
});
});
27 changes: 20 additions & 7 deletions src/helpers/tweet/__tests__/format-tweet-text.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,25 @@ import { Tweet } from "@the-convocation/twitter-scraper";
import { formatTweetText } from "../format-tweet-text.js";

describe("formatTweetText", () => {
it("should keep untouched a tweet without links", () => {
const tweet: Tweet = {
text: "This is a tweet without links.",
urls: [],
} as unknown as Tweet;
const result = formatTweetText(tweet);
expect(result).toStrictEqual("This is a tweet without links.");
describe("when the tweet has links", () => {
it("should remove the t.co links from the text", () => {
const tweet: Tweet = {
text: "This is a tweet with a link",
urls: ["https://t.co/abc123"],
} as unknown as Tweet;
const result = formatTweetText(tweet);
expect(result).toStrictEqual("This is a tweet with a link");
});
});

describe("when the tweet has media links", () => {
it("should remove the t.co links from the text", () => {
const tweet: Tweet = {
text: "This is a tweet with a media https://t.co/media123",
urls: [],
} as unknown as Tweet;
const result = formatTweetText(tweet);
expect(result).toStrictEqual("This is a tweet with a media");
});
});
});
54 changes: 54 additions & 0 deletions src/helpers/tweet/__tests__/get-eligible-tweet.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { Tweet } from "@the-convocation/twitter-scraper";

import { getEligibleTweet } from "../get-eligible-tweet.js";
import { keepRecentTweets, keepSelfQuotes, keepSelfReplies } from "../index.js";

jest.mock("../../../constants.js", () => {
return {
TWITTER_HANDLE: "username",
};
});
jest.mock("../index.js", () => {
return {
keepSelfReplies: jest.fn(),
keepSelfQuotes: jest.fn(),
keepRecentTweets: jest.fn(),
};
});

describe("getEligibleTweet", () => {
it.each`
isNotRetweet | isSelfReply | isSelfQuote | isRecentTweet | keep
${false} | ${false} | ${false} | ${false} | ${false}
${true} | ${true} | ${false} | ${false} | ${false}
${true} | ${false} | ${true} | ${false} | ${false}
${true} | ${false} | ${false} | ${true} | ${false}
${true} | ${true} | ${true} | ${true} | ${true}
`(
"should only return keep tweet when all conditions are met",
async ({ isNotRetweet, isSelfReply, isSelfQuote, isRecentTweet, keep }) => {
// Set mocks values
(keepSelfReplies as jest.Mock).mockReturnValue(isSelfReply);
(keepSelfQuotes as jest.Mock).mockReturnValue(isSelfQuote);
(keepRecentTweets as jest.Mock).mockReturnValue(isRecentTweet);

// Run test
const result = await getEligibleTweet({
isRetweet: !isNotRetweet,
} as unknown as Tweet);

// We're only checking for the keep status
expect(result).toStrictEqual(
keep
? {
inReplyToStatus: undefined,
inReplyToStatusId: undefined,
isRetweet: !isNotRetweet,
quotedStatus: undefined,
quotedStatusId: undefined,
}
: undefined,
);
},
);
});
10 changes: 10 additions & 0 deletions src/helpers/tweet/__tests__/get-tweet-id-from-permalink.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { getTweetIdFromPermalink } from "../get-tweet-id-from-permalink.js";

describe("getTweetIdFromPermalink", () => {
it("should return the tweet id", () => {
const result = getTweetIdFromPermalink(
"https://twitter.com/username/status/1234567890123456789",
);
expect(result).toBe("1234567890123456789");
});
});
21 changes: 21 additions & 0 deletions src/helpers/tweet/__tests__/is-tweet-cached.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Tweet } from "@the-convocation/twitter-scraper";

import { isTweetCached } from "../is-tweet-cached.js";

describe("isTweetCached", () => {
it("should return true if the tweet is cached", () => {
const result = isTweetCached(
{ id: "1234567890123456789" } as unknown as Tweet,
{
"1234567890123456789": {
mastodon: "mastodonId",
bluesky: {
cid: "cid",
rkey: "rkey",
},
},
},
);
expect(result).toBe(true);
});
});
23 changes: 23 additions & 0 deletions src/helpers/tweet/__tests__/keep-recent-tweets.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { Tweet } from "@the-convocation/twitter-scraper";

import { keepRecentTweets } from "../keep-recent-tweets.js";

describe("keepRecentTweets", () => {
describe("when the tweet is recent", () => {
it("should return true", () => {
const result = keepRecentTweets({
timestamp: Date.now(),
} as unknown as Tweet);
expect(result).toBe(true);
});
});

describe("when the tweet is old", () => {
it("should return false", () => {
const result = keepRecentTweets({
timestamp: new Date("1997-01-01").getTime(),
} as unknown as Tweet);
expect(result).toBe(false);
});
});
});
37 changes: 37 additions & 0 deletions src/helpers/tweet/__tests__/keep-self-quotes.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { Tweet } from "@the-convocation/twitter-scraper";

import { keepSelfQuotes } from "../keep-self-quotes.js";

jest.mock("../../../constants.js", () => {
return {
TWITTER_HANDLE: "username",
};
});

describe("keepSelfQuotes", () => {
describe("when the tweet is a quote", () => {
it("should return true when is from the same user", async () => {
const result = await keepSelfQuotes({
quotedStatus: { username: "username" },
} as unknown as Tweet);

expect(result).toBe(true);
});

it("should return false when is from a different user", async () => {
const result = await keepSelfQuotes({
quotedStatus: { username: "potatoinc" },
} as unknown as Tweet);

expect(result).toBe(false);
});
});

describe("when the tweet is not a quote", () => {
it("should return true when is from the same user", async () => {
const result = await keepSelfQuotes({} as unknown as Tweet);

expect(result).toBe(true);
});
});
});
37 changes: 37 additions & 0 deletions src/helpers/tweet/__tests__/keep-self-replies.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { Tweet } from "@the-convocation/twitter-scraper";

import { keepSelfReplies } from "../keep-self-replies.js";

jest.mock("../../../constants.js", () => {
return {
TWITTER_HANDLE: "username",
};
});

describe("keepSelfReplies", () => {
describe("when the tweet is a reply", () => {
it("should return true when is to the same user", async () => {
const result = await keepSelfReplies({
inReplyToStatus: { username: "username" },
} as unknown as Tweet);

expect(result).toBe(true);
});

it("should return false when is to a different user", async () => {
const result = await keepSelfReplies({
inReplyToStatus: { username: "potatoinc" },
} as unknown as Tweet);

expect(result).toBe(false);
});
});

describe("when the tweet is not a reply", () => {
it("should return true when is from the same user", async () => {
const result = await keepSelfReplies({} as unknown as Tweet);

expect(result).toBe(true);
});
});
});
4 changes: 2 additions & 2 deletions src/helpers/tweet/format-tweet-text.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Tweet } from "@the-convocation/twitter-scraper";

export const formatTweetText = (tweet: Tweet): string => {
let text = tweet.text || "";
let text = tweet.text ?? "";

// Replace urls
tweet.urls.forEach((url) => {
Expand All @@ -12,5 +12,5 @@ export const formatTweetText = (tweet: Tweet): string => {
text = text.replaceAll(/https:\/\/t\.co\/\w+/g, "");

// Return formatted
return text;
return text.trim();
};
2 changes: 1 addition & 1 deletion src/helpers/tweet/get-eligible-tweet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export const getEligibleTweet = async (
if (DEBUG && keep) {
console.log(
`✅ : ${tweet.id}: from:@${tweet.username}: ${getPostExcerpt(
tweet.text || "",
tweet.text ?? "",
)}`,
);
}
Expand Down
16 changes: 16 additions & 0 deletions src/helpers/url/__tests__/get-redirections.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { getRedirectedUrl } from "../get-redirection.js";

describe("getRedirectedUrl", () => {
describe("when the url is redirected", () => {
it("should return the final url", async () => {
const result = await getRedirectedUrl("https://t.co/bbJgfyzcJR");
expect(result).toStrictEqual("https://github.com/");
});
});
describe("when the url is not redirected", () => {
it("should return null", async () => {
const result = await getRedirectedUrl("https://t.co/_____null_____");
expect(result).toStrictEqual(null);
});
});
});
Loading

0 comments on commit 015699a

Please sign in to comment.