Skip to content

Commit

Permalink
Merge pull request #444 from lifeparticle/refactor-newsfeed
Browse files Browse the repository at this point in the history
Refactor newsfeed
  • Loading branch information
lifeparticle authored Mar 29, 2024
2 parents db02f09 + 708c5d1 commit cf7dbf3
Show file tree
Hide file tree
Showing 18 changed files with 401 additions and 455 deletions.
28 changes: 28 additions & 0 deletions api/newsfeed/helper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import xml2js from "xml2js";
export function parseXML(value) {
return new Promise((resolve, reject) => {
const parser = new xml2js.Parser({
explicitArray: false,
ignoreAttrs: true,
});
parser.parseString(value, (err, result) => {
if (err) reject(err);
else {
const items = result.rss.channel.item;
const list = items.map((item) => ({
title: item.title,
pubDate: item.pubDate,
url: item.link,
image: extractImage(item.description),
}));
resolve(list);
}
});
});
}

function extractImage(description) {
const regex = /<img.*?src=["'](.*?)["']/;
const match = regex.exec(description);
return match ? match[1] : null;
}
19 changes: 17 additions & 2 deletions api/newsfeed/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import express from "express";
import axios from "axios";
import { parseXML } from "./helper.js";

const app = express();
app.disable("x-powered-by");
Expand All @@ -23,6 +24,8 @@ app.get("/rss", async (req, res) => {
const sites = {
"frontend-focus": "https://cprss.s3.amazonaws.com/frontendfoc.us.xml",
"react-status": "https://cprss.s3.amazonaws.com/react.statuscode.com.xml",
"news-api":
"https://raw.githubusercontent.com/lifeparticle/binarytree/main/api/news/news.json",
};
const response = await axios.get(sites[sitename], {
responseType: "arraybuffer",
Expand All @@ -33,9 +36,21 @@ app.get("/rss", async (req, res) => {
}

res.setHeader("Cache-Control", "s-max-age=86400, stale-while-revalidate");
res.set("Content-Type", "application/xml");
res.set("Content-Type", "application/json");

res.send(response.data);
if (sitename === "news-api") res.send(response.data);

const xmlData = response.data.toString();

parseXML(xmlData)
.then((parsedData) => {
console.log(parsedData);
res.send({ articles: parsedData });
})
.catch((error) => {
console.error("Error parsing XML:", error);
res.status(500).json({ error: "Error parsing XML" });
});
} catch (error) {
if (error instanceof Error) {
res.status(500).json({ type: "error", message: error.message });
Expand Down
3 changes: 2 additions & 1 deletion api/newsfeed/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
"dependencies": {
"axios": "^1.5.0",
"express": "^4.18.2",
"rss-parser": "^3.13.0"
"rss-parser": "^3.13.0",
"xml2js": "^0.6.2"
},
"devDependencies": {
"nodemon": "^3.0.1"
Expand Down
11 changes: 11 additions & 0 deletions api/newsfeed/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1228,6 +1228,7 @@ __metadata:
express: ^4.18.2
nodemon: ^3.0.1
rss-parser: ^3.13.0
xml2js: ^0.6.2
languageName: unknown
linkType: soft

Expand Down Expand Up @@ -1896,6 +1897,16 @@ __metadata:
languageName: node
linkType: hard

"xml2js@npm:^0.6.2":
version: 0.6.2
resolution: "xml2js@npm:0.6.2"
dependencies:
sax: ">=0.6.0"
xmlbuilder: ~11.0.0
checksum: 458a83806193008edff44562c0bdb982801d61ee7867ae58fd35fab781e69e17f40dfeb8fc05391a4648c9c54012066d3955fe5d993ffbe4dc63399023f32ac2
languageName: node
linkType: hard

"xmlbuilder@npm:~11.0.0":
version: 11.0.1
resolution: "xmlbuilder@npm:11.0.1"
Expand Down
1 change: 1 addition & 0 deletions ui/.env.development
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
VITE_VERCEL_NEWS_FEED_URL=http://localhost:3000/rss?name=
1 change: 1 addition & 0 deletions ui/.env.production
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
VITE_VERCEL_NEWS_FEED_URL=https://binarytree-rssfeed-api.vercel.app/rss?name=
1 change: 1 addition & 0 deletions ui/.env.test
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
VITE_VERCEL_NEWS_FEED_URL=http://localhost:3000/rss?name=
4 changes: 4 additions & 0 deletions ui/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
### [10.6.1] - 2024-03-29

- Update Newsfeed tests

### [10.6.0] - 2024-01-24

- Added Information Page tests
Expand Down
4 changes: 2 additions & 2 deletions ui/src/pages/Newsfeed/Newsfeed.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ import style from "./Newsfeed.module.scss";
import useNewsFeed from "./useNewsFeed";

const Newsfeed: FC = () => {
const { data, isLoading, isError, setUrl } = useNewsFeed();
const { data, isLoading, isError, setTab } = useNewsFeed();

return (
<>
<Tabs
items={TAB_ITEMS}
onChange={(value) => {
setUrl(value);
setTab(value);
}}
className={style.newsfeed_tabs}
/>
Expand Down
84 changes: 0 additions & 84 deletions ui/src/pages/Newsfeed/__tests__/News.test.tsx

This file was deleted.

102 changes: 102 additions & 0 deletions ui/src/pages/Newsfeed/__tests__/Newsfeed.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// component
import Newsfeed from "pages/Newsfeed";
// dependencies
import { vi } from "vitest";
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
// hooks
import useNewsFeed from "pages/Newsfeed/useNewsFeed";
// types
import { ListSearchResultsProps } from "components/ComponentInjector/ListSearchResults/ListSearchResults";
import { TAB_ITEMS } from "pages/Newsfeed/constants";

vi.mock("pages/Newsfeed/useNewsFeed");

type Items = unknown[];

const mockListSearchResultsProps = vi.fn();
vi.mock("components/ComponentInjector", () => ({
ListSearchResults: (props: ListSearchResultsProps<Items>) => {
mockListSearchResultsProps(props);
return <div data-testid="list-search-results" />;
},
}));

const mockSetTab = vi.fn();

// Mock the useNewsFeed hook
vi.mock("./useNewsFeed", () => ({
data: [], // Assume empty data for simplicity
isLoading: false,
isError: false,
setTab: mockSetTab,
}));

const user = userEvent.setup();

describe("News component", () => {
const mockSetTab = vi.fn();
const newsFeedData = ["some data"];

// Setup phase
beforeEach(() => {
vi.mocked(useNewsFeed).mockReturnValue({
data: newsFeedData,
isLoading: false,
isError: false,
setTab: mockSetTab,
});

render(<Newsfeed />);
});

it("renders search results list", () => {
// Assert phase for the search results list
const listSearchResults = screen.getByTestId("list-search-results");
expect(listSearchResults).toBeInTheDocument();
});

it("calls mockListSearchResultsProps with correct arguments", () => {
// Assert phase for mock function call
expect(mockListSearchResultsProps).toHaveBeenCalledWith({
isError: false,
isLoading: false,
itemComponent: expect.any(Function),
items: ["some data"],
resourceName: "news",
});
});

describe("Tabs functionality", () => {
// Setup phase for tabs, run only if TAB_ITEMS is defined
let tabs: HTMLElement[];
beforeEach(() => {
tabs = screen.getAllByRole("tab");
});

it("renders the correct number of tabs", () => {
// Assert phase for the number of tabs

expect(tabs).toHaveLength(TAB_ITEMS.length);
});

it("renders tabs with correct labels", () => {
// Assert phase for tab labels
TAB_ITEMS.forEach((tabItem, index) => {
expect(tabs[index]).toHaveTextContent(tabItem.label);
});
});

it("calls setTab with the new tab value on tab change", async () => {
// This example simulates clicking the second tab
const secondTab = TAB_ITEMS[1];
await user.click(
screen.getByRole("tab", { name: secondTab.label })
);

// Verify setTab was called with the value of the second tab
expect(mockSetTab).toHaveBeenCalledWith(secondTab.key);
mockSetTab.mockClear();
});
});
});
51 changes: 0 additions & 51 deletions ui/src/pages/Newsfeed/__tests__/helper.test.ts

This file was deleted.

Loading

0 comments on commit cf7dbf3

Please sign in to comment.