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
9 changes: 9 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -169,9 +169,18 @@ jobs:
keycloak.cache-from=type=gha,scope=keycloak-${{ github.ref }}
keycloak.cache-from=type=gha,scope=keycloak-refs/heads/main
keycloak.cache-to=type=gha,scope=keycloak-${{ github.ref }}-e2e,mode=max
-
name: Generate Mock Server Certificates
run: |
openssl req -x509 -newkey rsa:2048 -keyout e2e/mock-server/key.pem -out e2e/mock-server/cert.pem \
-days 365 -nodes -subj '/CN=mock-server' \
-addext 'subjectAltName=DNS:openlibrary.org,DNS:covers.openlibrary.org,DNS:gutendex.com'
-
name: Start Services
run: docker compose up --wait --no-build
-
name: Trust Mock Server Certificate
run: docker compose exec -T php update-ca-certificates
-
name: Update API Platform
if: ${{ github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && inputs.minimum-stability != 'stable') }}
Expand Down
31 changes: 31 additions & 0 deletions api/migrations/Version20260318100000.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

declare(strict_types=1);

namespace DoctrineMigrations;

use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;

final class Version20260318100000 extends AbstractMigration
{
#[\Override]
public function getDescription(): string
{
return 'Add ON DELETE CASCADE to bookmark.book_id foreign key';
}

#[\Override]
public function up(Schema $schema): void
{
$this->addSql('ALTER TABLE bookmark DROP CONSTRAINT FK_DA62921D16A2B381');
$this->addSql('ALTER TABLE bookmark ADD CONSTRAINT FK_DA62921D16A2B381 FOREIGN KEY (book_id) REFERENCES book (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
}

#[\Override]
public function down(Schema $schema): void
{
$this->addSql('ALTER TABLE bookmark DROP CONSTRAINT FK_DA62921D16A2B381');
$this->addSql('ALTER TABLE bookmark ADD CONSTRAINT FK_DA62921D16A2B381 FOREIGN KEY (book_id) REFERENCES book (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
}
}
7 changes: 7 additions & 0 deletions compose.e2e.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@ services:
aliases:
- openlibrary.org
- covers.openlibrary.org
- gutendex.com

php:
volumes:
- ./e2e/mock-server/cert.pem:/usr/local/share/ca-certificates/mock-server.crt:ro
depends_on:
- mock-openlibrary

pwa:
environment:
Expand Down
12 changes: 9 additions & 3 deletions e2e/mock-server/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ if (!fs.existsSync(KEY_PATH) || !fs.existsSync(CERT_PATH)) {
console.log("Generating self-signed certificates...");
execSync(
`openssl req -x509 -newkey rsa:2048 -keyout ${KEY_PATH} -out ${CERT_PATH} ` +
`-days 365 -nodes -subj '/CN=openlibrary.org' ` +
`-addext 'subjectAltName=DNS:openlibrary.org,DNS:covers.openlibrary.org'`
`-days 365 -nodes -subj '/CN=mock-server' ` +
`-addext 'subjectAltName=DNS:openlibrary.org,DNS:covers.openlibrary.org,DNS:gutendex.com'`
);
}

Expand All @@ -26,12 +26,18 @@ const server = https.createServer(
// Try direct file path first (e.g. /books/OL2055137M.json)
let filePath = path.join(MOCKS_DIR, host, url.pathname);

// Handle search.json?q=Title Author&limit=10 -> search/Title-Author.json
// Handle openlibrary search: /search.json?q=Title Author&limit=10 -> search/Title-Author.json
if (url.pathname === "/search.json" && url.searchParams.has("q")) {
const query = url.searchParams.get("q").replace(/\s+/g, "-");
filePath = path.join(MOCKS_DIR, host, "search", `${query}.json`);
}

// Handle gutendex search: /books?search=... -> always return search/Asimov.json
// (MUI Autocomplete triggers additional searches with the full selected label)
if (host === "gutendex.com" && url.pathname === "/books" && url.searchParams.has("search")) {
filePath = path.join(MOCKS_DIR, host, "search", "Asimov.json");
}

if (fs.existsSync(filePath)) {
const ext = path.extname(filePath);
res.writeHead(200, {
Expand Down
13 changes: 13 additions & 0 deletions e2e/tests/admin/pages/AbstractPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,18 @@ export abstract class AbstractPage {
await this.page.route(/^https:\/\/covers\.openlibrary.org\/b\/id\/(.+)\.jpg$/, (route) => route.fulfill({
path: "tests/mocks/covers.openlibrary.org/b/id/4066031-M.jpg",
}));
// Gutendex mocks — always return the same search results (MUI Autocomplete
// triggers additional searches with the full selected label as query)
await this.page.route(/^https:\/\/gutendex\.com\/books\?search=/, (route) => {
return route.fulfill({
path: "tests/mocks/gutendex.com/search/Asimov.json",
});
});
await this.page.route(/^https:\/\/gutendex\.com\/books\/(\d+)\.json$/, (route) => {
const match = route.request().url().match(/\/books\/(\d+)\.json/);
return route.fulfill({
path: `tests/mocks/gutendex.com/books/${match?.[1]}.json`,
});
});
}
}
18 changes: 18 additions & 0 deletions e2e/tests/mocks/gutendex.com/books/31547.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"id": 31547,
"title": "Let's Get Together",
"authors": [
{
"name": "Asimov, Isaac",
"birth_year": 1920,
"death_year": 1992
}
],
"subjects": ["Science fiction"],
"bookshelves": [],
"languages": ["en"],
"copyright": false,
"media_type": "Text",
"formats": {},
"download_count": 1000
}
18 changes: 18 additions & 0 deletions e2e/tests/mocks/gutendex.com/books/41547.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"id": 41547,
"title": "The Genetic Effects of Radiation",
"authors": [
{
"name": "Asimov, Isaac",
"birth_year": 1920,
"death_year": 1992
}
],
"subjects": ["Science"],
"bookshelves": [],
"languages": ["en"],
"copyright": false,
"media_type": "Text",
"formats": {},
"download_count": 500
}
43 changes: 43 additions & 0 deletions e2e/tests/mocks/gutendex.com/search/Asimov.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{
"count": 2,
"next": null,
"previous": null,
"results": [
{
"id": 31547,
"title": "Let's Get Together",
"authors": [
{
"name": "Asimov, Isaac",
"birth_year": 1920,
"death_year": 1992
}
],
"subjects": ["Science fiction"],
"bookshelves": [],
"languages": ["en"],
"copyright": false,
"media_type": "Text",
"formats": {},
"download_count": 1000
},
{
"id": 41547,
"title": "The Genetic Effects of Radiation",
"authors": [
{
"name": "Asimov, Isaac",
"birth_year": 1920,
"death_year": 1992
}
],
"subjects": ["Science"],
"bookshelves": [],
"languages": ["en"],
"copyright": false,
"media_type": "Text",
"formats": {},
"download_count": 500
}
]
}
Loading