Skip to content

Commit

Permalink
test: Add test for real-world EPUB generation
Browse files Browse the repository at this point in the history
  • Loading branch information
spring-raining committed Jan 20, 2024
1 parent 053381a commit bbeba42
Show file tree
Hide file tree
Showing 4 changed files with 174 additions and 1 deletion.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
"devDependencies": {
"@hyrious/esbuild-plugin-commonjs": "^0.2.2",
"@release-it/conventional-changelog": "^5.1.1",
"@types/adm-zip": "^0.5.5",
"@types/archiver": "^5.3.2",
"@types/command-exists": "1.2.0",
"@types/debug": "^4.1.7",
Expand All @@ -85,6 +86,7 @@
"@types/w3c-xmlserializer": "^2.0.2",
"@types/whatwg-mimetype": "^3.0.0",
"@vitest/coverage-v8": "^0.33.0",
"adm-zip": "^0.5.10",
"esbuild": "^0.18.11",
"file-type": "^16.5.3",
"fs-extra": "^11.1.1",
Expand Down
49 changes: 49 additions & 0 deletions tests/__snapshots__/epub.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -281,3 +281,52 @@ exports[`generate EPUB from single HTML with pub manifest > tree 1`] = `
└─ publication.json
└─ output.epub"
`;
exports[`generate EPUB from single Markdown input > tree 1`] = `
"/
├─ tmp/
│ ├─ 1/
│ │ ├─ index.html
│ │ └─ publication.json
│ └─ 2/
│ ├─ EPUB/
│ │ ├─ content.opf
│ │ ├─ index.xhtml
│ │ └─ toc.ncx
│ └─ META-INF/
│ └─ container.xml
└─ work/
├─ input/
│ ├─ .vs-0.index.html
│ ├─ .vs-0.publication.json
│ └─ index.md
└─ output.epub"
`;
exports[`generate EPUB from vivliostyle.config.js > tree 1`] = `
"/
├─ tmp/
│ ├─ 1/
│ │ ├─ index.html
│ │ ├─ manuscript.html
│ │ ├─ my-theme.css
│ │ └─ publication.json
│ └─ 2/
│ ├─ EPUB/
│ │ ├─ content.opf
│ │ ├─ index.xhtml
│ │ ├─ manuscript.xhtml
│ │ ├─ my-theme.css
│ │ └─ toc.ncx
│ └─ META-INF/
│ └─ container.xml
└─ work/
└─ input/
├─ index.html
├─ manuscript.html
├─ manuscript.md
├─ my-theme.css
├─ output.epub
├─ publication.json
└─ vivliostyle.config.json"
`;
112 changes: 111 additions & 1 deletion tests/epub.test.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
import AdmZip from 'adm-zip';
import { fs as memfs, vol } from 'memfs';
import { format } from 'prettier';
import tmp from 'tmp';
import { afterEach, expect, it, vi } from 'vitest';
import { exportEpub } from '../src/output/epub.js';
import { buildWebPublication } from '../src/output/webbook.js';
import {
compile,
copyAssets,
prepareThemeDirectory,
} from '../src/processor/compile.js';
import { PublicationManifest } from '../src/schema/publication.schema.js';
import { toTree } from './commandUtil.js';
import { upath } from '../vendors/index.js';
import { getMergedConfig, toTree } from './commandUtil.js';

vi.mock('node:fs', () => ({ ...memfs, default: memfs }));

Expand All @@ -24,11 +32,42 @@ vi.mock('tmp', () => {
return { default: mod };
});

vi.mock('archiver', async () => {
const { default: archiver } = await vi.importActual<{
default: typeof import('archiver');
}>('archiver');
return {
default: (...args: Parameters<typeof archiver>) => {
const archive = archiver(...args);
archive.directory = (dirpath, destpath) => {
for (const p in vol.toJSON(dirpath, undefined, true)) {
archive.append(vol.readFileSync(upath.join(dirpath, p)), {
name: upath.join(destpath, p),
});
}
return archive;
};
return archive;
},
};
});

afterEach(() => {
vol.reset();
(tmp as any).__count = 0;
});

function checkValidEpubZip(epub: Buffer) {
// Check epub file contains uncompressed mimetype file
expect(epub.readUInt32BE(0)).toBe(0x504b0304);
expect(epub.readUInt16LE(8)).toBe(0);
expect(epub.slice(30, 38).toString()).toBe('mimetype');
expect(epub.slice(38, 58).toString()).toBe('application/epub+zip');
// Check the remaining files are compressed
expect(epub.readUInt32BE(58)).toBe(0x504b0304);
expect(epub.readUInt16LE(66)).not.toBe(0);
}

it('generate EPUB from single HTML with pub manifest', async () => {
const manifest: PublicationManifest = {
'@context': ['https://schema.org', 'https://www.w3.org/ns/pub-context'],
Expand Down Expand Up @@ -194,3 +233,74 @@ it('generate EPUB from series of HTML files', async () => {
'src/index.xhtml',
);
});

it('generate EPUB from single Markdown input', async () => {
vol.fromJSON({
'/work/input/index.md': '# Hello',
});
const config = await getMergedConfig([
'/work/input/index.md',
'--output',
'/work/output.epub',
]);
await compile(config);
await copyAssets(config);
await buildWebPublication({
...config,
target: config.outputs[0],
});

expect(toTree(vol).replace(/\.vs-[^.]+/g, '.vs-0')).toMatchSnapshot('tree');

const epub = vol.readFileSync('/work/output.epub') as Buffer;
checkValidEpubZip(epub);
const zipFiles = new AdmZip(epub).getEntries();
expect(
zipFiles.reduce((acc, z) => {
acc[z.entryName] = z.getData().toString();
return acc;
}, {}),
).toEqual({
mimetype: 'application/epub+zip',
...vol.toJSON('/tmp/2', undefined, true),
});
});

it('generate EPUB from vivliostyle.config.js', async () => {
vol.fromJSON({
'/work/input/vivliostyle.config.json': JSON.stringify({
entry: 'manuscript.md',
output: './output.epub',
theme: './my-theme.css',
toc: true,
}),
'/work/input/manuscript.md': '# Hello',
'/work/input/my-theme.css': '/* theme CSS */',
});
const config = await getMergedConfig([
'-c',
'/work/input/vivliostyle.config.json',
]);
await prepareThemeDirectory(config);
await compile(config);
await copyAssets(config);
await buildWebPublication({
...config,
target: config.outputs[0],
});

expect(toTree(vol)).toMatchSnapshot('tree');

const epub = vol.readFileSync('/work/input/output.epub') as Buffer;
checkValidEpubZip(epub);
const zipFiles = new AdmZip(epub).getEntries();
expect(
zipFiles.reduce((acc, z) => {
acc[z.entryName] = z.getData().toString();
return acc;
}, {}),
).toEqual({
mimetype: 'application/epub+zip',
...vol.toJSON('/tmp/2', undefined, true),
});
});
12 changes: 12 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -677,6 +677,13 @@
resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf"
integrity sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==

"@types/adm-zip@^0.5.5":
version "0.5.5"
resolved "https://registry.yarnpkg.com/@types/adm-zip/-/adm-zip-0.5.5.tgz#4588042726aa5f351d7ea88232e4a952f60e7c1a"
integrity sha512-YCGstVMjc4LTY5uK9/obvxBya93axZOVOyf2GSUulADzmLhYE45u2nAssCs/fWBs1Ifq5Vat75JTPwd5XZoPJw==
dependencies:
"@types/node" "*"

"@types/archiver@^5.3.2":
version "5.3.2"
resolved "https://registry.yarnpkg.com/@types/archiver/-/archiver-5.3.2.tgz#a9f0bcb0f0b991400e7766d35f6e19d163bdadcc"
Expand Down Expand Up @@ -1178,6 +1185,11 @@ add-stream@^1.0.0:
resolved "https://registry.yarnpkg.com/add-stream/-/add-stream-1.0.0.tgz#6a7990437ca736d5e1288db92bd3266d5f5cb2aa"
integrity sha512-qQLMr+8o0WC4FZGQTcJiKBVC59JylcPSrTtk6usvmIDFUOCKegapy1VHQwRbFMOFyb/inzUVqHs+eMYKDM1YeQ==

adm-zip@^0.5.10:
version "0.5.10"
resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.5.10.tgz#4a51d5ab544b1f5ce51e1b9043139b639afff45b"
integrity sha512-x0HvcHqVJNTPk/Bw8JbLWlWoo6Wwnsug0fnYYro1HBrjxZ3G7/AZk7Ahv8JwDe1uIcz8eBqvu86FuF1POiG7vQ==

agent-base@6, agent-base@^6.0.0, agent-base@^6.0.2:
version "6.0.2"
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77"
Expand Down

0 comments on commit bbeba42

Please sign in to comment.