mirror of
https://github.com/jaypyles/Scraperr.git
synced 2025-12-16 12:46:07 +00:00
fix: add cypress tests to CI [skip ci]
This commit is contained in:
38
.github/actions/run-cypress-tests/action.yaml
vendored
Normal file
38
.github/actions/run-cypress-tests/action.yaml
vendored
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
name: Run Cypress Tests
|
||||||
|
|
||||||
|
description: Run Cypress tests
|
||||||
|
|
||||||
|
runs:
|
||||||
|
using: "composite"
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Node
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 22
|
||||||
|
|
||||||
|
- name: Setup Docker project
|
||||||
|
shell: bash
|
||||||
|
run: docker compose up -d
|
||||||
|
|
||||||
|
- name: Wait for frontend to be ready
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
for i in {1..10}; do
|
||||||
|
curl -s http://127.0.0.1:3000 && echo "Frontend is ready" && exit 0
|
||||||
|
echo "Waiting for frontend to be ready... attempt $i"
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
echo "Frontend failed to be ready after 10 retries"
|
||||||
|
exit 1
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
shell: bash
|
||||||
|
run: npm install
|
||||||
|
|
||||||
|
- name: Run Cypress tests
|
||||||
|
shell: bash
|
||||||
|
run: npm run cy:run
|
||||||
|
|
||||||
9
.github/workflows/unit-tests.yml
vendored
9
.github/workflows/unit-tests.yml
vendored
@@ -27,3 +27,12 @@ jobs:
|
|||||||
|
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: PYTHONPATH=. pdm run pytest api/backend/tests
|
run: PYTHONPATH=. pdm run pytest api/backend/tests
|
||||||
|
|
||||||
|
cypress-tests:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Run Cypress tests
|
||||||
|
uses: ./.github/actions/run-cypress-tests/action.yaml
|
||||||
|
|||||||
@@ -2,10 +2,10 @@ import logging
|
|||||||
from typing import Any, Optional
|
from typing import Any, Optional
|
||||||
import random
|
import random
|
||||||
|
|
||||||
from bs4 import BeautifulSoup
|
from bs4 import BeautifulSoup, Tag
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
from seleniumwire import webdriver # type: ignore
|
from seleniumwire import webdriver # type: ignore
|
||||||
from lxml.etree import _Element # pyright: ignore [reportPrivateUsage]
|
from lxml.etree import _Element
|
||||||
from fake_useragent import UserAgent
|
from fake_useragent import UserAgent
|
||||||
from selenium.webdriver.chrome.options import Options as ChromeOptions
|
from selenium.webdriver.chrome.options import Options as ChromeOptions
|
||||||
from urllib.parse import urlparse, urljoin
|
from urllib.parse import urlparse, urljoin
|
||||||
@@ -16,7 +16,6 @@ from api.backend.job.site_mapping.site_mapping import (
|
|||||||
from selenium.webdriver.chrome.service import Service
|
from selenium.webdriver.chrome.service import Service
|
||||||
from webdriver_manager.chrome import ChromeDriverManager
|
from webdriver_manager.chrome import ChromeDriverManager
|
||||||
from api.backend.job.scraping.scraping_utils import scrape_content
|
from api.backend.job.scraping.scraping_utils import scrape_content
|
||||||
from api.backend.job.models.site_map import SiteMap
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -143,7 +142,10 @@ async def make_site_request(
|
|||||||
soup = BeautifulSoup(page_source, "html.parser")
|
soup = BeautifulSoup(page_source, "html.parser")
|
||||||
|
|
||||||
for a_tag in soup.find_all("a"):
|
for a_tag in soup.find_all("a"):
|
||||||
link = a_tag.get("href")
|
if not isinstance(a_tag, Tag):
|
||||||
|
continue
|
||||||
|
|
||||||
|
link = str(a_tag.get("href", ""))
|
||||||
|
|
||||||
if link:
|
if link:
|
||||||
if not urlparse(link).netloc:
|
if not urlparse(link).netloc:
|
||||||
@@ -171,7 +173,7 @@ async def collect_scraped_elements(page: tuple[str, str], xpaths: list[Element])
|
|||||||
el = sxpath(root, elem.xpath)
|
el = sxpath(root, elem.xpath)
|
||||||
|
|
||||||
for e in el:
|
for e in el:
|
||||||
if isinstance(e, etree._Element):
|
if isinstance(e, etree._Element): # type: ignore
|
||||||
text = "\t".join(str(t) for t in e.itertext())
|
text = "\t".join(str(t) for t in e.itertext())
|
||||||
else:
|
else:
|
||||||
text = str(e)
|
text = str(e)
|
||||||
@@ -194,7 +196,7 @@ async def scrape(
|
|||||||
headers: Optional[dict[str, Any]],
|
headers: Optional[dict[str, Any]],
|
||||||
multi_page_scrape: bool = False,
|
multi_page_scrape: bool = False,
|
||||||
proxies: Optional[list[str]] = [],
|
proxies: Optional[list[str]] = [],
|
||||||
site_map: Optional[SiteMap] = None,
|
site_map: Optional[dict[str, Any]] = None,
|
||||||
):
|
):
|
||||||
visited_urls: set[str] = set()
|
visited_urls: set[str] = set()
|
||||||
pages: set[tuple[str, str]] = set()
|
pages: set[tuple[str, str]] = set()
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
describe("Job", () => {
|
describe.only("Job", () => {
|
||||||
it("should create a job", () => {
|
it("should create a job", () => {
|
||||||
cy.visit("/");
|
cy.visit("/");
|
||||||
|
|
||||||
@@ -15,5 +15,16 @@ describe("Job", () => {
|
|||||||
|
|
||||||
const submit = cy.contains("Submit");
|
const submit = cy.contains("Submit");
|
||||||
submit.click();
|
submit.click();
|
||||||
|
|
||||||
|
const previousJobs = cy.get("li").contains("Previous Jobs");
|
||||||
|
previousJobs.click();
|
||||||
|
|
||||||
|
const jobUrl = cy.get("div").contains("https://example.com");
|
||||||
|
jobUrl.should("exist");
|
||||||
|
|
||||||
|
cy.wait(10000);
|
||||||
|
|
||||||
|
const completedJobStatus = cy.get("div").contains("Completed");
|
||||||
|
completedJobStatus.should("exist");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -59,8 +59,8 @@ stubPath = ""
|
|||||||
|
|
||||||
# Type checking strictness
|
# Type checking strictness
|
||||||
typeCheckingMode = "strict" # Enables strict type checking mode
|
typeCheckingMode = "strict" # Enables strict type checking mode
|
||||||
reportPrivateUsage = "error"
|
reportPrivateUsage = "none"
|
||||||
reportMissingTypeStubs = "error"
|
reportMissingTypeStubs = "none"
|
||||||
reportUntypedFunctionDecorator = "error"
|
reportUntypedFunctionDecorator = "error"
|
||||||
reportUntypedClassDecorator = "error"
|
reportUntypedClassDecorator = "error"
|
||||||
reportUntypedBaseClass = "error"
|
reportUntypedBaseClass = "error"
|
||||||
|
|||||||
Reference in New Issue
Block a user