Skip to content

Commit 7002fbc

Browse files
Merge pull request #9 from Eric-Zhang-Developer/feature/backend-logic
Feature/backend logic
2 parents beba11f + b35fde8 commit 7002fbc

File tree

8 files changed

+7775
-2500
lines changed

8 files changed

+7775
-2500
lines changed

jest.config.mjs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import nextJest from "next/jest.js";
2+
3+
const createJestConfig = nextJest({
4+
dir: "./",
5+
});
6+
7+
const config = {
8+
testEnvironment: "jest-environment-jsdom",
9+
setupFilesAfterEnv: ["<rootDir>/jest.setup.js"],
10+
};
11+
12+
export default createJestConfig(config);

jest.setup.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
import "@testing-library/jest-dom";

package-lock.json

Lines changed: 7621 additions & 2499 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
"dev": "next dev --turbopack",
77
"build": "next build",
88
"start": "next start",
9-
"lint": "next lint"
9+
"lint": "next lint",
10+
"test": "jest"
1011
},
1112
"dependencies": {
1213
"next": "15.2.3",
@@ -17,11 +18,16 @@
1718
"devDependencies": {
1819
"@eslint/eslintrc": "^3",
1920
"@tailwindcss/postcss": "^4",
21+
"@testing-library/jest-dom": "^6.6.3",
22+
"@testing-library/react": "^16.3.0",
23+
"@types/jest": "^30.0.0",
2024
"@types/node": "^20",
2125
"@types/react": "^19",
2226
"@types/react-dom": "^19",
2327
"eslint": "^9",
2428
"eslint-config-next": "15.2.3",
29+
"jest": "^30.0.2",
30+
"jest-environment-jsdom": "^30.0.2",
2531
"tailwindcss": "^4",
2632
"typescript": "^5"
2733
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import Compare from "../comparison";
2+
3+
describe("Comparison Tests", () => {
4+
describe("Core Logic", () => {
5+
it("should return an array of users who are in the following list but not the followers list", () => {
6+
const followers = ["Alice", "Brenda"];
7+
const following = ["Alice", "Brenda", "Charlie"];
8+
const result = Compare(following, followers);
9+
10+
expect(result).toEqual(["Charlie"]);
11+
});
12+
13+
it("should return an empty array when both lists are empty", () => {
14+
const followers: string[] = [];
15+
const following: string[] = [];
16+
const result = Compare(following, followers);
17+
18+
expect(result).toEqual([]);
19+
});
20+
21+
it("should return the entire following list if there are not followers to compare to", () => {
22+
const followers: string[] = [];
23+
const following = ["Alice", "Brenda", "Charlie", "David"];
24+
const result = Compare(following, followers);
25+
26+
expect(result).toEqual(following);
27+
});
28+
});
29+
30+
describe("Business Logic", () => {
31+
it("should return ex-friend if my ex-friend unfollowed me", () => {
32+
const followers = ["friend"];
33+
const following = ["friend", "ex_friend"];
34+
const result = Compare(following, followers);
35+
36+
expect(result).toEqual(["ex_friend"]);
37+
});
38+
39+
it("should return only celebrities that I expect when no one unfollows me", () => {
40+
const followers = ["friend", "friend_2"];
41+
const following = ["friend", "friend_2", "POTUS", "Tom_Cruise"];
42+
const result = Compare(following, followers);
43+
44+
expect(result).toEqual(["POTUS", "Tom_Cruise"]);
45+
});
46+
47+
it("should return no accounts when I don't follow accounts who follow me", () => {
48+
const followers = ["friend", "friend_2", "spam_bot"];
49+
const following = ["friend", "friend_2"];
50+
const result = Compare(following, followers);
51+
52+
expect(result).toEqual([]);
53+
});
54+
55+
it("should return ex-friend AND celebrity accounts when my ex-friend unfollows me and I follow brand / celerity accounts I don't expect to follow me back", () => {
56+
const followers = ["friend"];
57+
const following = ["friend", "ex_friend", "POTUS", "Tom_Cruise"];
58+
const result = Compare(following, followers);
59+
60+
expect(result).toEqual(["ex_friend", "POTUS", "Tom_Cruise"]);
61+
});
62+
63+
});
64+
});
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import ExtractNamesFromJson from "../extractNamesFromJson";
2+
3+
const data = [
4+
{
5+
title: "",
6+
media_list_data: [],
7+
string_list_data: [
8+
{
9+
href: "https://www.instagram.com/POTUS",
10+
value: "POTUS",
11+
timestamp: 2248397812,
12+
},
13+
],
14+
},
15+
{
16+
title: "",
17+
media_list_data: [],
18+
string_list_data: [
19+
{
20+
href: "https://www.instagram.com/NASA",
21+
value: "NASA",
22+
timestamp: 1267694584,
23+
},
24+
],
25+
},
26+
];
27+
28+
// Other tests are not necessary here because Typescript already validates the json as formed properly
29+
// If the json is bad then we throw an error outside
30+
31+
describe("Extract Names Function Tests", () => {
32+
describe("Core Logic", () => {
33+
// Happy path
34+
it("should return an array of usernames when a proper json is input", () => {
35+
const result = ExtractNamesFromJson(data);
36+
expect(result).toEqual(["POTUS", "NASA"]);
37+
});
38+
});
39+
});

src/lib/comparison.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Calculates the difference between two lists of users to find who is not following back.
2+
// Uses a set to reduce time from O(n*m) to O(n + m)
3+
// For each user name in your following it checks to see if its in the followers set, O(n) time total
4+
export default function Compare(followingData: string[], followerData: string[]) {
5+
const followerDataSet = new Set(followerData);
6+
const doesNotFollowBack = followingData.filter(userName => {
7+
return !followerDataSet.has(userName);
8+
});
9+
return doesNotFollowBack;
10+
}
11+
12+

src/lib/extractNamesFromJson.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// The reason for these interfaces is so that typescript neatly throws an error when a user
2+
// adds a json that is not a followers.json or following.json format
3+
4+
interface ExpectedJSON {
5+
title: string;
6+
media_list_data: unknown[];
7+
string_list_data: stringListData[];
8+
}
9+
10+
interface stringListData{
11+
href: string;
12+
value: string;
13+
timestamp: number;
14+
}
15+
16+
export default function ExtractNamesFromJson(json: ExpectedJSON[]) {
17+
const usernames = json.map(user => user.string_list_data[0].value);
18+
return usernames;
19+
}

0 commit comments

Comments
 (0)