feat: transition bestseller analysis storage to SQLite and add category blacklist
- Replaces Excel output with structured database tables for tracking category analysis runs and product results. - Implements a blacklist to exclude specific category IDs from the bestseller pipeline. - Adds unit tests for category processing and enhances logging with levels and timestamps. - Introduces foreign key enforcement and updated schema definitions in the database module.
This commit is contained in:
99
src/bestsellers-by-category.test.ts
Normal file
99
src/bestsellers-by-category.test.ts
Normal file
@@ -0,0 +1,99 @@
|
||||
import { test, expect, beforeAll, afterAll, beforeEach, mock } from "bun:test";
|
||||
import { Database } from "bun:sqlite";
|
||||
import { getDb, initDb, closeDb } from "./database";
|
||||
import path from "node:path";
|
||||
import { rmSync, mkdirSync } from "node:fs";
|
||||
import {
|
||||
main,
|
||||
processCategory,
|
||||
insertCategoryRunSummary,
|
||||
insertProductAnalysisResults,
|
||||
} from "./bestsellers-by-category";
|
||||
import * as keepaModule from "./keepa";
|
||||
import * as spApiModule from "./sp-api";
|
||||
import * as llmModule from "./llm";
|
||||
|
||||
const DB_TEST_PATH = path.join(
|
||||
process.cwd(),
|
||||
"test_output",
|
||||
"test_analysis.sqlite",
|
||||
);
|
||||
|
||||
let db: Database;
|
||||
|
||||
beforeAll(() => {
|
||||
// Ensure the test output directory exists and is clean
|
||||
rmSync(path.dirname(DB_TEST_PATH), { recursive: true, force: true });
|
||||
mkdirSync(path.dirname(DB_TEST_PATH), { recursive: true });
|
||||
initDb(DB_TEST_PATH);
|
||||
db = getDb(DB_TEST_PATH);
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
closeDb();
|
||||
rmSync(path.dirname(DB_TEST_PATH), { recursive: true, force: true });
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
// Clear tables before each test if necessary, or use a fresh DB for each test
|
||||
// For simplicity, we'll assume tables are clean after initDb in beforeAll
|
||||
// and not clear for each test if data is not interdependent.
|
||||
});
|
||||
|
||||
test("processCategory function test", async () => {
|
||||
const mockCategory = {
|
||||
id: 1,
|
||||
label: "Category 1",
|
||||
parentId: 0,
|
||||
childCount: 0,
|
||||
};
|
||||
|
||||
const summary = await processCategory(db, mockCategory, 2);
|
||||
|
||||
expect(summary.status).toBe("ok");
|
||||
expect(summary.categoryId).toBe(mockCategory.id);
|
||||
expect(summary.categoryLabel).toBe(mockCategory.label);
|
||||
expect(summary.topAsinsChecked).toBe(2);
|
||||
expect(summary.availableAsins).toBe(2);
|
||||
expect(summary.fba).toBe(1);
|
||||
expect(summary.fbm).toBe(1);
|
||||
expect(summary.skip).toBe(0);
|
||||
expect(summary.results?.length).toBe(2);
|
||||
|
||||
const runId = await insertCategoryRunSummary(
|
||||
db,
|
||||
summary,
|
||||
new Date().toISOString(),
|
||||
);
|
||||
if (summary.results) {
|
||||
await insertProductAnalysisResults(db, runId, summary.results);
|
||||
}
|
||||
|
||||
// Verify category run summary insertion
|
||||
const categoryRun = db
|
||||
.query("SELECT * FROM category_analysis_runs")
|
||||
.all() as any[];
|
||||
expect(categoryRun.length).toBe(1);
|
||||
expect(categoryRun[0].category_label).toBe("Category 1");
|
||||
expect(categoryRun[0].top_asins_checked).toBe(2);
|
||||
expect(categoryRun[0].available_asins).toBe(2);
|
||||
expect(categoryRun[0].fba_count).toBe(1);
|
||||
expect(categoryRun[0].fbm_count).toBe(1);
|
||||
expect(categoryRun[0].status).toBe("ok");
|
||||
|
||||
// Verify product analysis results insertion
|
||||
const productResults = db
|
||||
.query("SELECT * FROM product_analysis_results ORDER BY asin")
|
||||
.all() as any[];
|
||||
expect(productResults.length).toBe(2);
|
||||
|
||||
expect(productResults[0].asin).toBe("B000000001");
|
||||
expect(productResults[0].name).toBe("Product One");
|
||||
expect(productResults[0].verdict).toBe("FBA");
|
||||
expect(productResults[0].run_id).toBe(categoryRun[0].id);
|
||||
|
||||
expect(productResults[1].asin).toBe("B000000002");
|
||||
expect(productResults[1].name).toBe("Product Two");
|
||||
expect(productResults[1].verdict).toBe("FBM");
|
||||
expect(productResults[1].run_id).toBe(categoryRun[0].id);
|
||||
});
|
||||
Reference in New Issue
Block a user