Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,20 @@ jobs:
with:
node-version: 24
- run: npm install
- run: npx playwright install chromium --with-deps
- name: Get Playwright version
id: pw-version
run: echo "version=$(npx playwright --version | awk '{print $2}')" >> $GITHUB_OUTPUT
- name: Cache Playwright browsers
uses: actions/cache@v4
id: pw-cache
with:
path: ~/.cache/ms-playwright
key: playwright-${{ runner.os }}-${{ steps.pw-version.outputs.version }}
- name: Install Playwright browsers
if: steps.pw-cache.outputs.cache-hit != 'true'
run: npx playwright install chromium --with-deps
- name: Install Playwright deps only
if: steps.pw-cache.outputs.cache-hit == 'true'
run: npx playwright install-deps chromium
- run: node test/smoke-test.js

4 changes: 2 additions & 2 deletions lib/sources/ebay.js
Original file line number Diff line number Diff line change
Expand Up @@ -1234,7 +1234,7 @@ export async function searchActive(
const { value: ent, stale } = await cacheGetStale(ACTIVE_CACHE_COL, dk);
if (ent?.itemsByCountry) {
if (stale && !cp) {
searchActive({ query, relevanceQuery, deliveryCountries, languages, config, refresh: true, noEbay: false, getToken, on401 }).catch(() => {});
searchActive({ query, relevanceQuery, deliveryCountries: deliveryCountriesOpt, languages: languagesOpt, config, refresh: true, noEbay: false, getToken, on401 }).catch(() => {});
}
return ent;
}
Expand Down Expand Up @@ -1614,7 +1614,7 @@ export async function searchSold(
const { value: cached, stale } = await cacheGetStale(SOLD_CACHE_COL, soldDk);
if (cached?.items) {
if (stale && !cp) {
searchSold({ query, relevanceQuery, languages, config, refresh: true, noEbay: false, getToken, on401, soldBrowser }).catch(() => {});
searchSold({ query, relevanceQuery, languages: languagesOpt, config, refresh: true, noEbay: false, getToken, on401, soldBrowser }).catch(() => {});
}
return {
items: cached.items,
Expand Down
39 changes: 39 additions & 0 deletions test/smoke-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,45 @@ async function run() {
await mobile.close();
await page.close();

// --- Portfolio section ---
console.log("\n[Portfolio section]");
const portfolioPage = await browser.newPage();
await portfolioPage.goto(BASE);
assert(await portfolioPage.locator("#portfolio-section").isVisible(), "portfolio section visible on landing");
assert(await portfolioPage.locator("#portfolio-load").isVisible(), "portfolio load button visible");
await portfolioPage.close();

// --- Portfolio API endpoints ---
console.log("\n[Portfolio API]");
const apiPage = await browser.newPage();

const portfolioRes = await apiPage.goto(`${BASE}/api/portfolio?demo=true`);
assert(portfolioRes.status() === 200, "portfolio demo returns 200");
const portfolioBody = await portfolioRes.json();
assert(portfolioBody.cards?.length === 3, "demo portfolio has 3 cards");
assert(typeof portfolioBody.roiPercent === "number", "portfolio has roiPercent");

const historyRes = await apiPage.goto(`${BASE}/api/portfolio/history?demo=true&days=7`);
assert(historyRes.status() === 200, "portfolio history returns 200");
const historyBody = await historyRes.json();
assert(historyBody.history?.length === 7, "portfolio history returns 7 entries");

const csvCheck = await apiPage.evaluate(async (base) => {
const r = await fetch(`${base}/api/portfolio/export?format=csv&demo=true`);
return { status: r.status, ct: r.headers.get("content-type"), body: await r.text() };
}, BASE);
assert(csvCheck.status === 200, "portfolio CSV export returns 200");
assert(csvCheck.ct?.includes("text/csv"), "CSV export has text/csv content-type");
assert(csvCheck.body.includes("Card ID"), "CSV has header row");

const gradingRes = await apiPage.goto(`${BASE}/api/portfolio/grading-opportunities?demo=true`);
assert(gradingRes.status() === 200, "grading opportunities returns 200");
const gradingBody = await gradingRes.json();
assert(gradingBody.opportunities?.length === 2, "2 grading opportunities (Umbreon + Greninja)");
assert(gradingBody.skipped?.length === 1, "1 skipped (Pikachu PSA 10)");

await apiPage.close();

// --- Static assets ---
console.log("\n[Static assets]");
const page2 = await browser.newPage();
Expand Down
Loading