From ed3aae0a36c0ff684527c0ebbdaa64091ef5680e Mon Sep 17 00:00:00 2001 From: maximfromit Date: Wed, 21 Aug 2024 04:55:14 +0300 Subject: [PATCH] final initial commit --- .gitignore | 1 + index.js | 172 ++++++++++++++++++----------------- source | 162 --------------------------------- tests/sortHackerNews.test.js | 32 ++++--- 4 files changed, 109 insertions(+), 258 deletions(-) delete mode 100644 source diff --git a/.gitignore b/.gitignore index d68bdb9..5fb7a4a 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ node_modules/ /playwright-report/ /blob-report/ /playwright/.cache/ +why_qa_wolf.txt diff --git a/index.js b/index.js index e2bf968..d8728b7 100644 --- a/index.js +++ b/index.js @@ -1,81 +1,78 @@ -import { test, expect, chromium } from "@playwright/test" +import { chromium } from "@playwright/test" import dayjs from "dayjs" -import { link } from "fs" import l from "lodash" -const getNews = async (page) => { +const extractNewsData = async (page) => { console.log("Extracting article data...") const newsData = await page.evaluate(() => { const rows = Array.from(document.querySelectorAll("tr[id]")) return rows .map((row) => { - let time = null const id = row.getAttribute("id") // Find the element with text matching the rank pattern - const isMaxThreeDigitsAndDot = (value) => { - return /^\d{1,3}\.$/.test(value) - } - const findedRank = () => { - const findedRankByClassRank = Array.from( - row.querySelectorAll(".rank") - ).find((el) => { - const text = el.textContent.trim() - return isMaxThreeDigitsAndDot(text) - }) - const findedRankByAllRow = Array.from(row.querySelectorAll("*")).find( + const isMaxThreeDigitsAndDot = (value) => /^\d{1,3}\.$/.test(value) + const findRank = () => { + const rankByClass = Array.from(row.querySelectorAll(".rank")).find( (el) => { const text = el.textContent.trim() return isMaxThreeDigitsAndDot(text) } ) - if (!!findedRankByClassRank) - return parseInt( - findedRankByClassRank.textContent.trim().replace(".", ""), - 10 - ) - if (!!findedRankByAllRow) + const rankByAllElements = Array.from(row.querySelectorAll("*")).find( + (el) => { + const text = el.textContent.trim() + return isMaxThreeDigitsAndDot(text) + } + ) + if (!!rankByClass) + return parseInt(rankByClass.textContent.trim().replace(".", ""), 10) + if (!!rankByAllElements) return parseInt( - findedRankByAllRow.textContent.trim().replace(".", ""), + rankByAllElements.textContent.trim().replace(".", ""), 10 ) return null } - let sibling = row.nextElementSibling - - while (sibling && !sibling.getAttribute("id")) { - const isTime = (value) => - /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}$/.test(value) - - const findedTime = () => { - const findedTimeInTitle = Array.from( - sibling.querySelectorAll("*") - ).find((el) => isTime(el.getAttribute("title"))) - const findedTimeInAttributes = Array.from( - sibling.querySelectorAll("*") - ).find((el) => { - return Array.from(el.attributes).some((attr) => - isTime(attr.value) - ) - }) - - if (findedTimeInTitle) - return findedTimeInTitle.getAttribute("title") - if (findedTimeInAttributes) { - return Array.from(findedTimeInAttributes.attributes).find( - (attr) => isTime(attr.value) - ).value + + const findTimeInsideSibling = (sibling) => { + if (!!sibling && !sibling.getAttribute("id")) { + const isTime = (value) => + /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}$/.test(value) + + const findedTime = () => { + const findedTimeInTitle = Array.from( + sibling.querySelectorAll("*") + ).find((el) => isTime(el.getAttribute("title"))) + const findedTimeInAttributes = Array.from( + sibling.querySelectorAll("*") + ).find((el) => { + return Array.from(el.attributes).some((attr) => + isTime(attr.value) + ) + }) + + if (findedTimeInTitle) + return findedTimeInTitle.getAttribute("title") + if (findedTimeInAttributes) { + return Array.from(findedTimeInAttributes.attributes).find( + (attr) => isTime(attr.value) + ).value + } + return null } - return null - } - if (findedTime()) { - time = findedTime() - break + if (!!findedTime()) return findedTime() + return findTimeInsideSibling(row.nextElementSibling) } - sibling = sibling.nextElementSibling + return null + } + + return { + id: id ?? null, + rank: findRank(), + time: findTimeInsideSibling(row.nextElementSibling), } - return { id: id ?? null, rank: findedRank(), time } }) .filter((item) => item.id !== null && item.rank !== null) }) @@ -83,7 +80,7 @@ const getNews = async (page) => { return newsData } -export const sortHackerNewsArticles = async () => { +export const fetchAndSortHackerNewsArticles = async () => { const browser = await chromium.launch({ headless: false }) const context = await browser.newContext() const page = await context.newPage() @@ -100,27 +97,23 @@ export const sortHackerNewsArticles = async () => { console.log("Page loaded.") - let combinedNewsData = [] + let allNewsData = [] let highestRank = 0 - let initialNumber = 1 - const executeUntilTrue = async () => { - const newNews = await getNews(page) + const fetchNewsUntilConditionMet = async () => { + const newNews = await extractNewsData(page) if (l.isEmpty(newNews)) { console.log("ERROR IN FETCHING DATA") return } - if ( - !l.isEmpty(combinedNewsData) && - combinedNewsData[0].rank === newNews[0].rank - ) { + if (!l.isEmpty(allNewsData) && allNewsData[0].rank === newNews[0].rank) { console.log("ERROR IN PAGE ITERATION") return } - combinedNewsData = l.concat(combinedNewsData, newNews) - highestRank = l.maxBy(combinedNewsData, "rank").rank + allNewsData = l.concat(allNewsData, newNews) + highestRank = l.maxBy(allNewsData, "rank").rank if (highestRank < 100) { initialNumber = initialNumber + newNews.length @@ -134,16 +127,16 @@ export const sortHackerNewsArticles = async () => { await page.goto(`${testPage}?n=${initialNumber}`) await page.waitForTimeout(2000) // Wait for new content to load - await executeUntilTrue() + await fetchNewsUntilConditionMet() } else { console.log("Condition met!") } } - await executeUntilTrue() + await fetchNewsUntilConditionMet() const newsWithRankLessThan101 = l.filter( - combinedNewsData, + allNewsData, (item) => item.rank <= 100 ) console.log(newsWithRankLessThan101) @@ -152,37 +145,33 @@ export const sortHackerNewsArticles = async () => { } catch (error) { console.error("AN ERROR OCCURRED:", error) } finally { - // await browser.close() + await browser.close() } } -;(async () => { - await sortHackerNewsArticles() -})() -// Test functions const runTests = async () => { - const newsWithRankLessThan101 = await sortHackerNewsArticles() + const latest100News = await fetchAndSortHackerNewsArticles() console.log("Running tests...") - // Test 1: Check if news array exists - if (!l.isEmpty(newsWithRankLessThan101)) { + // Test 1: Verify news array existence + if (!l.isEmpty(latest100News)) { console.log("Test 1 passed: News array exists.") } else { console.error("Test 1 failed: News array does not exist.") } - // Test 2: Check if length of newsWithRankLessThan100 is 100 - if (newsWithRankLessThan101.length === 100) { + // Test 2: Verify length of latest100News is 100 + if (latest100News.length === 100) { console.log("Test 2 passed: Length of news array is 100.") } else { console.error( - `Test 2 failed: Length of news array is ${newsWithRankLessThan101.length}.` + `Test 2 failed: Length of news array is ${latest100News.length}.` ) } - // Test 3: Check if there are news with ranks from 1 to 100 - const ranks = l.map(newsWithRankLessThan101, "rank") + // Test 3: Verify ranks from 1 to 100 are present + const ranks = l.map(latest100News, "rank") const allRanksPresent = l.every(l.range(1, 101), (rank) => l.includes(ranks, rank) ) @@ -192,8 +181,19 @@ const runTests = async () => { console.error("Test 3 failed: Not all ranks from 1 to 100 are present.") } - // Test 4: Check if articles are sorted from newest to oldest - const sorted = l.every(newsWithRankLessThan101, (item, index, array) => { + // Test 4: Verify ranks are sequential from 1 to 100 + const ranksInCorrectOrder = l.every( + latest100News, + (item, index) => item.rank === index + 1 + ) + if (ranksInCorrectOrder) { + console.log("Test 4 passed: Ranks are sequential from 1 to 100.") + } else { + console.error("Test 4 failed: Ranks are not sequential from 1 to 100.") + } + + // Test 5: Verify articles are sorted from newest to oldest + const sorted = l.every(latest100News, (item, index, array) => { if (index === 0) return true const currentItemDate = dayjs(item.time) const previousItemDate = dayjs(array[index - 1].time) @@ -203,10 +203,14 @@ const runTests = async () => { ) }) if (sorted) { - console.log("Test 4 passed: Articles are sorted from newest to oldest.") + console.log("Test 5 passed: Articles are sorted from newest to oldest.") } else { - console.error("Test 4 failed: Articles are not sorted correctly.") + console.error("Test 5 failed: Articles are not sorted correctly.") } } runTests() + +// ;(async () => { +// await fetchAndSortHackerNewsArticles() +// })() diff --git a/source b/source deleted file mode 100644 index d121c34..0000000 --- a/source +++ /dev/null @@ -1,162 +0,0 @@ - - - 1. -
Digital License Plates and the Deal That Never Had a Chance (eff.org) - 1 point by hn_acker 1 minute ago | hide | past | discuss - - - - 2.
Uncensored AI: a fine tune of Llama 405B – no more PC nonsense (aiuncensored.info) - 1 point by saroyas 6 minutes ago | hide | past | discuss - - - - 3.
Ask HN: Is America best at the world in anything anymore? - 1 point by atleastoptimal 6 minutes ago | hide | past | 2 comments - - - - 4.
Cloud Security List – A list of cloud security tools and open source projects (github.com/someengineering) - 1 point by scapecast 15 minutes ago | hide | past | discuss - - - - 5.
A graphic adventure: the 25-year rise and fall of a beloved genre (2011) (arstechnica.com) - 1 point by adamrmcd 21 minutes ago | hide | past | discuss - - - - 6.
Prosthetic sixth finger, so you can claim any pictures of you are AI generated [video] (youtube.com) - 1 point by ta8645 21 minutes ago | hide | past | discuss - - - - 7.
Eli Lilly Says Weight-Loss Drug Sharply Reduces Diabetes Progression (wsj.com) - 1 point by bookofjoe 21 minutes ago | hide | past | 1 comment - - - - 8.
Elon Musk's 23 active lawsuits (fortune.com) - 2 points by elsewhen 21 minutes ago | hide | past | 1 comment - - - - 9.
Leveling up from vibes-based engineering (forestfriends.tech) - 1 point by iamwil 23 minutes ago | hide | past | discuss - - - - 10.
Texas Sues General Motors for Billions over Decade-Long Data Theft [video] (youtube.com) - 1 point by kklisura 24 minutes ago | hide | past | discuss - - - - 11.
Old Tesla Model 3 performance beats new model [video] (youtube.com) - 2 points by garyclarke27 25 minutes ago | hide | past | discuss - - - - 12.
Popular AI "nudify" sites sued amid rise in victims globally (arstechnica.com) - 2 points by e12e 32 minutes ago | hide | past | discuss - - - - 13.
Managing Change and Minimizing Whiplash on Engineering Teams (compromised.dev) - 1 point by tsmango 33 minutes ago | hide | past | discuss - - - - 14.
Phone maker Nothing: staff back into the office 5 days/week or quit (fortune.com) - 5 points by dmitrygr 34 minutes ago | hide | past | 1 comment - - - - 15.
RAG Is Laughably Simple - 2 points by josvdwest 34 minutes ago | hide | past | 1 comment - - - - 16.
Artificial Intelligence Predicts Earthquakes with Unprecedented Accuracy (scitechdaily.com) - 2 points by geox 42 minutes ago | hide | past | discuss - - - - 17.
Jlama – a modern LLM inference engine for Java (github.com/tjake) - 1 point by simonpure 44 minutes ago | hide | past | discuss - - - - 18.
Travel to Iceland and Let Horses Reply to Your Email (visiticeland.com) - 2 points by alishobeiri 46 minutes ago | hide | past | 1 comment - - - - 19.
Unhackable Phone Created by Former Pegasus Spyware Developer [video] (youtube.com) - 1 point by RadixDLT 48 minutes ago | hide | past | discuss - - - - 20.
80% of programmers are not happy (youtube.com) - 2 points by afpx 49 minutes ago | hide | past | discuss - - - - 21.
Uv: An fast Python package and project manager, written in Rust (github.com/astral-sh) - 1 point by ot 49 minutes ago | hide | past | discuss - - - - 22.
v0.dev: Generate UI, run code, build apps (twitter.com/v0) - 2 points by leerob 49 minutes ago | hide | past | discuss - - - - 23.
Iran named as source of Trump campaign phish, leaks (theregister.com) - 2 points by LinuxBender 51 minutes ago | hide | past | discuss - - - - 24.
Critical Jenkins vulnerability added to CISA's known vulnerabilities catalog (scmagazine.com) - 1 point by LinuxBender 51 minutes ago | hide | past | discuss - - - - 25.
Critical Flaw in Donation Plugin Exposed 100k WordPress Sites to Takeover (securityweek.com) - 2 points by LinuxBender 52 minutes ago | hide | past | discuss - - - - 26.
Archinstall 2.8.2 to Speed Up Arch Linux Installations, Other Fixes (phoronix.com) - 1 point by LinuxBender 52 minutes ago | hide | past | discuss - - - - 27.
How I Select Which Ideas to Build: A Personal Approach (nittarab.substack.com) - 1 point by Nittarab 56 minutes ago | hide | past | discuss - - - - 28.
AWS Configuration Issue Could Expose Web Apps (wired.com) - 3 points by holografix 57 minutes ago | hide | past | discuss - - - - 29.
Recogni Introduces Pareto AI Math, Changing How the World Runs Generative AI (recogni.com) - 1 point by flyaway123 57 minutes ago | hide | past | discuss - - - - 30.
Show HN: Monitor Postgres Replication Slots via Slack (peerdb.io) - 1 point by saisrirampur 57 minutes ago | hide | past | discuss - - - - - - -

-
Consider applying for YC's first-ever Fall batch! Applications are open till Aug 27.

-
Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

-
Search:
- - diff --git a/tests/sortHackerNews.test.js b/tests/sortHackerNews.test.js index 9bd8afd..402de72 100644 --- a/tests/sortHackerNews.test.js +++ b/tests/sortHackerNews.test.js @@ -1,34 +1,42 @@ import { test, expect } from "@playwright/test" -import { sortHackerNewsArticles } from "../index" // Adjust the path if necessary +import { fetchAndSortHackerNewsArticles } from "../index" // Adjust the path if necessary import l from "lodash" import dayjs from "dayjs" -let newsWithRankLessThan100 +let latest100News -test.describe("Hacker News Articles Sorting Tests", () => { +test.describe("Hacker News Articles Sorting", () => { // Fetch data once before all tests test.beforeAll(async () => { - newsWithRankLessThan100 = await sortHackerNewsArticles() + latest100News = await fetchAndSortHackerNewsArticles() }) - test("Check if news array exists", async () => { - expect(!l.isEmpty(newsWithRankLessThan100)).toBe(true) + test("Verify news array existence", async () => { + expect(!l.isEmpty(latest100News)).toBe(true) }) - test("Check if length of newsWithRankLessThan100 is 100", async () => { - expect(newsWithRankLessThan100.length).toBe(100) + test("Verify length of latest100News is 100", async () => { + expect(latest100News.length).toBe(100) }) - test("Check if there are news with ranks from 1 to 100", async () => { - const ranks = l.map(newsWithRankLessThan100, "rank") + test("Verify ranks from 1 to 100 are present", async () => { + const ranks = l.map(latest100News, "rank") const allRanksPresent = l.every(l.range(1, 101), (rank) => l.includes(ranks, rank) ) expect(allRanksPresent).toBe(true) }) - test("Check if articles are sorted from newest to oldest", async () => { - const sorted = l.every(newsWithRankLessThan100, (item, index, array) => { + test("Verify ranks are sequential from 1 to 100", async () => { + const ranksInCorrectOrder = l.every( + latest100News, + (item, index) => item.rank === index + 1 + ) + expect(ranksInCorrectOrder).toBe(true) + }) + + test("Verify articles are sorted from newest to oldest", async () => { + const sorted = l.every(latest100News, (item, index, array) => { if (index === 0) return true const currentItemDate = dayjs(item.time) const previousItemDate = dayjs(array[index - 1].time)