Repository navigation
Develop #22
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Develop #22
Changes from all commits
eace90b
4374c4a
83577c2
3373953
a38535e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -17,4 +17,7 @@ coverage/ | |
| frontend/coverage/ | ||
| backend/coverage/ | ||
| *.lcov | ||
| .nyc_output/ | ||
| .nyc_output/ | ||
|
|
||
| # Dist-electron | ||
| dist-electron/ | ||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -1,11 +1,35 @@ | ||||||
| import "dotenv/config"; | ||||||
| import express from "express"; | ||||||
| import { existsSync } from "fs"; | ||||||
| import path from "path"; | ||||||
| import { createJobsApiApp } from "./jobsApiApp.js"; | ||||||
|
|
||||||
| const PORT = Number(process.env.PORT || 3001); | ||||||
| const app = createJobsApiApp({ | ||||||
| outputDir: path.resolve(process.cwd(), "output"), | ||||||
| }); | ||||||
|
|
||||||
| // When running inside Electron, main.js sets ELECTRON_OUTPUT_DIR to a | ||||||
| // writable user-data path. Fall back to the CWD-relative folder for dev/CLI. | ||||||
| const outputDir = process.env.ELECTRON_OUTPUT_DIR | ||||||
| ? process.env.ELECTRON_OUTPUT_DIR | ||||||
| : path.resolve(process.cwd(), "output"); | ||||||
|
|
||||||
| const app = createJobsApiApp({ outputDir }); | ||||||
|
|
||||||
| // ── Electron static-file serving ─────────────────────────────────────────── | ||||||
| // When ELECTRON_STATIC_DIR is set, serve the React production build so that | ||||||
| // the Electron window can load everything from http://localhost:<PORT>. | ||||||
| const staticDir = process.env.ELECTRON_STATIC_DIR; | ||||||
| if (staticDir && existsSync(staticDir)) { | ||||||
| app.use(express.static(staticDir)); | ||||||
|
|
||||||
| // SPA catch-all: return index.html for any non-API route so that React | ||||||
| // Router (if used in future) works correctly. | ||||||
| app.use((req, res) => { | ||||||
| if (req.path.startsWith("/api")) { | ||||||
| return res.status(404).json({ error: "Rota não encontrada." }); | ||||||
|
||||||
| return res.status(404).json({ error: "Rota não encontrada." }); | |
| return res.status(404).json({ message: "Rota não encontrada." }); |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -1,24 +1,45 @@ | ||||||
| import path from "path"; | ||||||
| import { beforeEach, describe, expect, it, vi } from "vitest"; | ||||||
|
|
||||||
| const mocks = vi.hoisted(() => ({ | ||||||
| listen: vi.fn(), | ||||||
| use: vi.fn(), | ||||||
| createJobsApiApp: vi.fn(), | ||||||
| consoleLog: vi.fn(), | ||||||
| existsSync: vi.fn(), | ||||||
| staticMiddleware: vi.fn(), | ||||||
| expressStatic: vi.fn(), | ||||||
| })); | ||||||
|
|
||||||
| mocks.createJobsApiApp.mockReturnValue({ | ||||||
| listen: mocks.listen, | ||||||
| use: mocks.use, | ||||||
| }); | ||||||
|
|
||||||
| mocks.expressStatic.mockReturnValue(mocks.staticMiddleware); | ||||||
|
|
||||||
| vi.mock("../../../src/jobsApiApp.js", () => ({ | ||||||
| createJobsApiApp: mocks.createJobsApiApp, | ||||||
| })); | ||||||
|
|
||||||
| vi.mock("fs", () => ({ | ||||||
| existsSync: mocks.existsSync, | ||||||
| })); | ||||||
|
|
||||||
| vi.mock("express", () => ({ | ||||||
| default: { | ||||||
| static: mocks.expressStatic, | ||||||
| }, | ||||||
| })); | ||||||
|
|
||||||
| describe("server entry", () => { | ||||||
| beforeEach(() => { | ||||||
| vi.resetModules(); | ||||||
| vi.clearAllMocks(); | ||||||
| process.env.PORT = "3100"; | ||||||
| delete process.env.ELECTRON_STATIC_DIR; | ||||||
| delete process.env.ELECTRON_OUTPUT_DIR; | ||||||
| mocks.existsSync.mockReturnValue(false); | ||||||
| vi.spyOn(console, "log").mockImplementation(mocks.consoleLog); | ||||||
| }); | ||||||
|
|
||||||
|
|
@@ -41,4 +62,46 @@ describe("server entry", () => { | |||||
|
|
||||||
| expect(mocks.listen).toHaveBeenCalledWith(3001, expect.any(Function)); | ||||||
| }); | ||||||
|
|
||||||
| it("usa ELECTRON_OUTPUT_DIR quando definido", async () => { | ||||||
| process.env.ELECTRON_OUTPUT_DIR = "/tmp/electron-output"; | ||||||
|
|
||||||
| await import("../../../src/server.js"); | ||||||
|
|
||||||
| expect(mocks.createJobsApiApp).toHaveBeenCalledWith({ | ||||||
| outputDir: "/tmp/electron-output", | ||||||
| }); | ||||||
| }); | ||||||
|
|
||||||
| it("registra static e fallback SPA quando ELECTRON_STATIC_DIR existe", async () => { | ||||||
| process.env.ELECTRON_STATIC_DIR = "/tmp/frontend-dist"; | ||||||
| mocks.existsSync.mockReturnValue(true); | ||||||
|
|
||||||
| await import("../../../src/server.js"); | ||||||
|
|
||||||
| expect(mocks.expressStatic).toHaveBeenCalledWith("/tmp/frontend-dist"); | ||||||
| expect(mocks.use).toHaveBeenCalledTimes(2); | ||||||
| expect(mocks.use).toHaveBeenNthCalledWith(1, mocks.staticMiddleware); | ||||||
|
|
||||||
| const fallbackHandler = mocks.use.mock.calls[1][0]; | ||||||
|
|
||||||
| const apiRes = { | ||||||
| status: vi.fn().mockReturnThis(), | ||||||
| json: vi.fn(), | ||||||
| sendFile: vi.fn(), | ||||||
| }; | ||||||
| fallbackHandler({ path: "/api/unknown" }, apiRes); | ||||||
| expect(apiRes.status).toHaveBeenCalledWith(404); | ||||||
| expect(apiRes.json).toHaveBeenCalledWith({ error: "Rota não encontrada." }); | ||||||
|
||||||
| expect(apiRes.json).toHaveBeenCalledWith({ error: "Rota não encontrada." }); | |
| expect(apiRes.json).toHaveBeenCalledWith({ message: "Rota não encontrada." }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
runScraper()usagetConfig()(que lêOUTPUT_FILE/PDF_FILEdoprocess.env) para decidir onde gravar os arquivos, mas este endpoint lista/retorna arquivos a partir deoutputDir(opção docreateJobsApiApp). SeoutputDirfor customizado (ex.: em testes/uso embutido), o scraper pode escrever em outro diretório e a resposta pode não refletir o resultado do run. Considere alinhar o diretório de output do scraper comoutputDir(passando config para o scraper ou setando env defaults com base emoutputDir).