mirror of
https://github.com/blasten/turn.js.git
synced 2026-07-14 05:41:08 +08:00
add tests and graphic corrections
This commit is contained in:
parent
9ceba31662
commit
f4cfeb954d
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
node_modules/
|
||||||
|
test-results/
|
||||||
|
playwright-report/
|
||||||
@ -24,43 +24,61 @@
|
|||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.book-frame {
|
||||||
|
width: min(720px, calc(100vw - 56px));
|
||||||
|
aspect-ratio: 72 / 46;
|
||||||
|
}
|
||||||
|
|
||||||
#book {
|
#book {
|
||||||
width: 720px;
|
width: 100%;
|
||||||
height: 460px;
|
height: 100%;
|
||||||
background: #cbd3df;
|
background: #cbd3df;
|
||||||
}
|
}
|
||||||
|
|
||||||
#book .page {
|
#book .page {
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 16px;
|
|
||||||
width: 360px;
|
|
||||||
height: 460px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
padding: 28px;
|
|
||||||
border: 1px solid #aeb8c8;
|
|
||||||
background: #fff8df;
|
background: #fff8df;
|
||||||
font-size: 18px;
|
overflow: hidden;
|
||||||
line-height: 1.2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#book .page:nth-child(even) {
|
#book .page.alt {
|
||||||
background: #e7f1ff;
|
background: #e7f1ff;
|
||||||
}
|
}
|
||||||
|
|
||||||
#book .page h1,
|
#book .page-content {
|
||||||
#book .page h2 {
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 16px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
padding: 28px;
|
||||||
|
border: 1px solid #aeb8c8;
|
||||||
|
font-size: 18px;
|
||||||
|
line-height: 1.2;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
#book .page.alt .page-content {
|
||||||
|
background: #e7f1ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
#book .page:not(.alt) .page-content {
|
||||||
|
background: #fff8df;
|
||||||
|
}
|
||||||
|
|
||||||
|
#book .page-content h1,
|
||||||
|
#book .page-content h2 {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-size: 30px;
|
font-size: 30px;
|
||||||
line-height: 1.05;
|
line-height: 1.05;
|
||||||
}
|
}
|
||||||
|
|
||||||
#book .page p {
|
#book .page-content p {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
line-height: 1.45;
|
line-height: 1.45;
|
||||||
}
|
}
|
||||||
|
|
||||||
#book .page img {
|
#book .page-content img {
|
||||||
display: block;
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 180px;
|
height: 180px;
|
||||||
@ -104,53 +122,76 @@
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 820px) {
|
@media (max-width: 620px) {
|
||||||
#book {
|
#book .page-content {
|
||||||
width: 92vw;
|
gap: 12px;
|
||||||
height: 58vw;
|
padding: 20px;
|
||||||
max-height: 460px;
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#book .page-content h1,
|
||||||
|
#book .page-content h2 {
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#book .page-content img {
|
||||||
|
height: 130px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<main>
|
<main>
|
||||||
<div id="book">
|
<div class="book-frame">
|
||||||
<div class="page">
|
<div id="book">
|
||||||
<span class="kicker">Demo minimale</span>
|
<div class="page">
|
||||||
<h1>Explorer turn.js</h1>
|
<div class="page-content">
|
||||||
<img src="assets/cover.svg" alt="Livre ouvert avec pages colorees">
|
<span class="kicker">Demo minimale</span>
|
||||||
<p>Un exemple autonome pour verifier rapidement le chargement de jQuery 4, l'initialisation du plugin et le changement de page.</p>
|
<h1>Explorer turn.js</h1>
|
||||||
</div>
|
<img src="assets/cover.svg" alt="Livre ouvert avec pages colorees">
|
||||||
<div class="page">
|
<p>Un exemple autonome pour verifier rapidement le chargement de jQuery 4, l'initialisation du plugin et le changement de page.</p>
|
||||||
<span class="kicker">Page 2</span>
|
</div>
|
||||||
<h2>Un livre HTML</h2>
|
</div>
|
||||||
<p>Chaque page est un simple element HTML. Le plugin ajoute les wrappers, gere les vues et anime le passage d'une page a l'autre.</p>
|
<div class="page alt">
|
||||||
<img src="assets/layout.svg" alt="Composition de pages dans un navigateur">
|
<div class="page-content">
|
||||||
</div>
|
<span class="kicker">Page 2</span>
|
||||||
<div class="page">
|
<h2>Un livre HTML</h2>
|
||||||
<span class="kicker">Page 3</span>
|
<p>Chaque page est un simple element HTML. Le plugin ajoute les wrappers, gere les vues et anime le passage d'une page a l'autre.</p>
|
||||||
<h2>Images et texte</h2>
|
<img src="assets/layout.svg" alt="Composition de pages dans un navigateur">
|
||||||
<img src="assets/media.svg" alt="Image abstraite avec cadres de contenu">
|
</div>
|
||||||
<p>La demo contient du texte et des images locales afin de tester un rendu un peu plus proche d'un cas reel.</p>
|
</div>
|
||||||
</div>
|
<div class="page">
|
||||||
<div class="page">
|
<div class="page-content">
|
||||||
<span class="kicker">Page 4</span>
|
<span class="kicker">Page 3</span>
|
||||||
<h2>Navigation</h2>
|
<h2>Images et texte</h2>
|
||||||
<p>Utilise les boutons, les fleches du clavier ou le coin de page pour changer de vue.</p>
|
<img src="assets/media.svg" alt="Image abstraite avec cadres de contenu">
|
||||||
<img src="assets/navigation.svg" alt="Fleches de navigation autour d'un livre">
|
<p>La demo contient du texte et des images locales afin de tester un rendu un peu plus proche d'un cas reel.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="page">
|
</div>
|
||||||
<span class="kicker">Page 5</span>
|
<div class="page alt">
|
||||||
<h2>Compatibilite</h2>
|
<div class="page-content">
|
||||||
<img src="assets/browser.svg" alt="Fenetre de navigateur avec indicateurs de compatibilite">
|
<span class="kicker">Page 4</span>
|
||||||
<p>Cette page charge jQuery 4.0.0 depuis le CDN officiel et la version locale de turn.js depuis le depot clone.</p>
|
<h2>Navigation</h2>
|
||||||
</div>
|
<p>Utilise les boutons, les fleches du clavier ou le coin de page pour changer de vue.</p>
|
||||||
<div class="page">
|
<img src="assets/navigation.svg" alt="Fleches de navigation autour d'un livre">
|
||||||
<span class="kicker">Page 6</span>
|
</div>
|
||||||
<h2>Fin du test</h2>
|
</div>
|
||||||
<p>Si cette derniere page s'affiche et que le retour fonctionne, le scenario minimal est operationnel.</p>
|
<div class="page">
|
||||||
<img src="assets/finish.svg" alt="Marque de validation sur une page">
|
<div class="page-content">
|
||||||
|
<span class="kicker">Page 5</span>
|
||||||
|
<h2>Compatibilite</h2>
|
||||||
|
<img src="assets/browser.svg" alt="Fenetre de navigateur avec indicateurs de compatibilite">
|
||||||
|
<p>Cette page charge jQuery 4.0.0 depuis le CDN officiel et la version locale de turn.js depuis le depot clone.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="page alt">
|
||||||
|
<div class="page-content">
|
||||||
|
<span class="kicker">Page 6</span>
|
||||||
|
<h2>Fin du test</h2>
|
||||||
|
<p>Si cette derniere page s'affiche et que le retour fonctionne, le scenario minimal est operationnel.</p>
|
||||||
|
<img src="assets/finish.svg" alt="Marque de validation sur une page">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -166,15 +207,34 @@
|
|||||||
<script>
|
<script>
|
||||||
$(function() {
|
$(function() {
|
||||||
var $book = $('#book');
|
var $book = $('#book');
|
||||||
|
var $frame = $('.book-frame');
|
||||||
var $status = $('#status');
|
var $status = $('#status');
|
||||||
|
|
||||||
|
function currentBookSize() {
|
||||||
|
var width = Math.floor($frame.width());
|
||||||
|
if (width % 2) width -= 1;
|
||||||
|
return {
|
||||||
|
width: width,
|
||||||
|
height: Math.round(width * 460 / 720)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function syncBookSize() {
|
||||||
|
var size = currentBookSize();
|
||||||
|
$frame.css('height', size.height);
|
||||||
|
$book.turn('size', size.width, size.height);
|
||||||
|
}
|
||||||
|
|
||||||
function updateStatus() {
|
function updateStatus() {
|
||||||
$status.text('Page ' + $book.turn('page') + ' / ' + $book.turn('pages'));
|
$status.text('Page ' + $book.turn('page') + ' / ' + $book.turn('pages'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var initialSize = currentBookSize();
|
||||||
|
$frame.css('height', initialSize.height);
|
||||||
|
|
||||||
$book.turn({
|
$book.turn({
|
||||||
width: 720,
|
width: initialSize.width,
|
||||||
height: 460,
|
height: initialSize.height,
|
||||||
display: 'double',
|
display: 'double',
|
||||||
gradients: true,
|
gradients: true,
|
||||||
acceleration: true,
|
acceleration: true,
|
||||||
@ -196,6 +256,8 @@
|
|||||||
if (event.key === 'ArrowRight') $book.turn('next');
|
if (event.key === 'ArrowRight') $book.turn('next');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$(window).on('resize.turnDemo', syncBookSize);
|
||||||
|
|
||||||
updateStatus();
|
updateStatus();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
1962
package-lock.json
generated
Normal file
1962
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
18
package.json
Normal file
18
package.json
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"name": "turn.js",
|
||||||
|
"version": "3.0.0-local",
|
||||||
|
"private": true,
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"test": "npm run test:unit && npm run test:visual",
|
||||||
|
"test:unit": "vitest run",
|
||||||
|
"test:visual": "playwright test",
|
||||||
|
"test:visual:update": "playwright test --update-snapshots"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@playwright/test": "1.60.0",
|
||||||
|
"jquery": "4.0.0",
|
||||||
|
"jsdom": "27.2.0",
|
||||||
|
"vitest": "^4.1.8"
|
||||||
|
}
|
||||||
|
}
|
||||||
21
playwright.config.mjs
Normal file
21
playwright.config.mjs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import { defineConfig } from '@playwright/test';
|
||||||
|
import { existsSync } from 'node:fs';
|
||||||
|
|
||||||
|
const chromiumExecutable = process.env.CHROMIUM_EXECUTABLE_PATH || '/usr/bin/chromium';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
testDir: './tests/visual',
|
||||||
|
timeout: 30_000,
|
||||||
|
expect: {
|
||||||
|
timeout: 5_000,
|
||||||
|
toHaveScreenshot: {
|
||||||
|
maxDiffPixelRatio: 0.02
|
||||||
|
}
|
||||||
|
},
|
||||||
|
use: {
|
||||||
|
browserName: 'chromium',
|
||||||
|
viewport: { width: 1100, height: 760 },
|
||||||
|
deviceScaleFactor: 1,
|
||||||
|
launchOptions: existsSync(chromiumExecutable) ? { executablePath: chromiumExecutable } : {}
|
||||||
|
}
|
||||||
|
});
|
||||||
143
tests/unit/turn.unit.test.js
Normal file
143
tests/unit/turn.unit.test.js
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
||||||
|
import { JSDOM } from 'jsdom';
|
||||||
|
import { createRequire } from 'node:module';
|
||||||
|
import { readFileSync } from 'node:fs';
|
||||||
|
import { fileURLToPath } from 'node:url';
|
||||||
|
import { dirname, resolve } from 'node:path';
|
||||||
|
|
||||||
|
const require = createRequire(import.meta.url);
|
||||||
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||||
|
const jqueryDist = dirname(require.resolve('jquery'));
|
||||||
|
const jquerySource = readFileSync(resolve(jqueryDist, 'jquery.js'), 'utf8');
|
||||||
|
const turnSource = readFileSync(resolve(__dirname, '../../turn.js'), 'utf8');
|
||||||
|
|
||||||
|
function createFixture(pageCount = 4) {
|
||||||
|
const pages = Array.from({ length: pageCount }, (_, index) => (
|
||||||
|
`<div class="page">Page ${index + 1}</div>`
|
||||||
|
)).join('');
|
||||||
|
|
||||||
|
const dom = new JSDOM(`<!doctype html><html><body><div id="book">${pages}</div></body></html>`, {
|
||||||
|
pretendToBeVisual: true,
|
||||||
|
runScripts: 'outside-only',
|
||||||
|
url: 'http://localhost/'
|
||||||
|
});
|
||||||
|
|
||||||
|
dom.window.eval(jquerySource);
|
||||||
|
const $ = dom.window.jQuery;
|
||||||
|
dom.window.eval(turnSource);
|
||||||
|
|
||||||
|
return { window: dom.window, document: dom.window.document, $ };
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('turn.js jQuery plugin', () => {
|
||||||
|
let fixture;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = createFixture();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
fixture.window.close();
|
||||||
|
vi.restoreAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('registers the turn, flip and transform plugins', () => {
|
||||||
|
const { $ } = fixture;
|
||||||
|
|
||||||
|
expect($.fn.turn).toBeTypeOf('function');
|
||||||
|
expect($.fn.flip).toBeTypeOf('function');
|
||||||
|
expect($.fn.transform).toBeTypeOf('function');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('initializes a book and exposes page, view, pages and size state', () => {
|
||||||
|
const { $ } = fixture;
|
||||||
|
const $book = $('#book');
|
||||||
|
|
||||||
|
$book.turn({
|
||||||
|
width: 600,
|
||||||
|
height: 400,
|
||||||
|
display: 'double',
|
||||||
|
gradients: false,
|
||||||
|
acceleration: false
|
||||||
|
});
|
||||||
|
|
||||||
|
expect($book.turn('page')).toBe(1);
|
||||||
|
expect($book.turn('pages')).toBe(4);
|
||||||
|
expect($book.turn('view')).toEqual([0, 1]);
|
||||||
|
expect($book.turn('size')).toEqual({ width: 600, height: 400 });
|
||||||
|
expect($book.find('.turn-page-wrapper').length).toBeGreaterThan(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('supports initial page selection without animation', () => {
|
||||||
|
const { $ } = fixture;
|
||||||
|
const $book = $('#book');
|
||||||
|
|
||||||
|
$book.turn({
|
||||||
|
width: 600,
|
||||||
|
height: 400,
|
||||||
|
display: 'double',
|
||||||
|
gradients: false,
|
||||||
|
acceleration: false,
|
||||||
|
page: 2
|
||||||
|
});
|
||||||
|
|
||||||
|
expect($book.turn('page')).toBe(2);
|
||||||
|
expect($book.turn('view')).toEqual([2, 3]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can add and remove pages dynamically', () => {
|
||||||
|
const { $ } = fixture;
|
||||||
|
const $book = $('#book');
|
||||||
|
|
||||||
|
$book.turn({
|
||||||
|
width: 600,
|
||||||
|
height: 400,
|
||||||
|
display: 'double',
|
||||||
|
gradients: false,
|
||||||
|
acceleration: false
|
||||||
|
});
|
||||||
|
|
||||||
|
$book.turn('addPage', $('<div class="page">Page 5</div>'), 5);
|
||||||
|
expect($book.turn('pages')).toBe(5);
|
||||||
|
expect($book.turn('hasPage', 5)).toBe(true);
|
||||||
|
|
||||||
|
$book.turn('removePage', 5);
|
||||||
|
expect($book.turn('pages')).toBe(4);
|
||||||
|
expect($book.turn('hasPage', 5)).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('registers internal handlers with event namespaces', () => {
|
||||||
|
fixture.window.close();
|
||||||
|
fixture = createFixture();
|
||||||
|
|
||||||
|
const { $ } = fixture;
|
||||||
|
const onSpy = vi.spyOn($.fn, 'on');
|
||||||
|
|
||||||
|
$('#book').turn({
|
||||||
|
width: 600,
|
||||||
|
height: 400,
|
||||||
|
display: 'double',
|
||||||
|
gradients: false,
|
||||||
|
acceleration: false,
|
||||||
|
when: {
|
||||||
|
turned: function() {}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const eventNames = onSpy.mock.calls
|
||||||
|
.map(call => call[0])
|
||||||
|
.filter(name => typeof name === 'string');
|
||||||
|
|
||||||
|
const pointerEvents = $.isTouch
|
||||||
|
? ['touchstart.turn', 'touchmove.turn', 'touchend.turn']
|
||||||
|
: ['mousedown.turn', 'mousemove.turn', 'mouseup.turn'];
|
||||||
|
|
||||||
|
expect(eventNames).toContain('turned.turn');
|
||||||
|
expect(eventNames).toEqual(expect.arrayContaining(pointerEvents));
|
||||||
|
expect(eventNames).toContain('pressed.turnFlip');
|
||||||
|
expect(eventNames).toContain('released.turnFlip');
|
||||||
|
expect(eventNames).toContain('start.turnFlip');
|
||||||
|
expect(eventNames).toContain('end.turnFlip');
|
||||||
|
expect(eventNames).toContain('flip.turnFlip');
|
||||||
|
});
|
||||||
|
});
|
||||||
148
tests/visual/minimal.spec.js
Normal file
148
tests/visual/minimal.spec.js
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
import { expect, test } from '@playwright/test';
|
||||||
|
import { createServer } from 'node:http';
|
||||||
|
import { readFile } from 'node:fs/promises';
|
||||||
|
import { createRequire } from 'node:module';
|
||||||
|
import { extname, join, normalize } from 'node:path';
|
||||||
|
import { fileURLToPath } from 'node:url';
|
||||||
|
import { dirname, resolve } from 'node:path';
|
||||||
|
|
||||||
|
const require = createRequire(import.meta.url);
|
||||||
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||||
|
const root = resolve(__dirname, '../..');
|
||||||
|
const jqueryDist = dirname(require.resolve('jquery'));
|
||||||
|
const jqueryPath = resolve(jqueryDist, 'jquery.min.js');
|
||||||
|
|
||||||
|
const contentTypes = {
|
||||||
|
'.html': 'text/html; charset=utf-8',
|
||||||
|
'.js': 'text/javascript; charset=utf-8',
|
||||||
|
'.svg': 'image/svg+xml; charset=utf-8'
|
||||||
|
};
|
||||||
|
|
||||||
|
let server;
|
||||||
|
let baseUrl;
|
||||||
|
|
||||||
|
test.beforeAll(async () => {
|
||||||
|
server = createServer(async (request, response) => {
|
||||||
|
try {
|
||||||
|
const url = new URL(request.url, 'http://127.0.0.1');
|
||||||
|
const pathname = url.pathname === '/' ? '/demos/minimal/index.html' : url.pathname;
|
||||||
|
const file = normalize(join(root, pathname));
|
||||||
|
|
||||||
|
if (!file.startsWith(root)) {
|
||||||
|
response.writeHead(403);
|
||||||
|
response.end('Forbidden');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const body = await readFile(file);
|
||||||
|
response.writeHead(200, {
|
||||||
|
'content-type': contentTypes[extname(file)] || 'application/octet-stream'
|
||||||
|
});
|
||||||
|
response.end(body);
|
||||||
|
} catch (error) {
|
||||||
|
response.writeHead(404);
|
||||||
|
response.end(error.message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
await new Promise(resolveListen => server.listen(0, '127.0.0.1', resolveListen));
|
||||||
|
baseUrl = `http://127.0.0.1:${server.address().port}`;
|
||||||
|
});
|
||||||
|
|
||||||
|
test.afterAll(async () => {
|
||||||
|
await new Promise(resolveClose => server.close(resolveClose));
|
||||||
|
});
|
||||||
|
|
||||||
|
test.beforeEach(async ({ page }) => {
|
||||||
|
await page.route('https://code.jquery.com/jquery-4.0.0.min.js', route => {
|
||||||
|
route.fulfill({
|
||||||
|
path: jqueryPath,
|
||||||
|
contentType: 'text/javascript; charset=utf-8'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('minimal demo renders the opening page', async ({ page }) => {
|
||||||
|
await page.goto(`${baseUrl}/demos/minimal/index.html`);
|
||||||
|
await page.waitForFunction(() => window.jQuery && window.jQuery.fn.jquery === '4.0.0' && typeof window.jQuery.fn.turn === 'function');
|
||||||
|
await expect(page.locator('#book')).toHaveScreenshot('minimal-book-page-1.png');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('minimal demo renders after turning to the next page', async ({ page }) => {
|
||||||
|
await page.goto(`${baseUrl}/demos/minimal/index.html`);
|
||||||
|
await page.waitForFunction(() => window.jQuery && window.jQuery.fn.jquery === '4.0.0' && typeof window.jQuery.fn.turn === 'function');
|
||||||
|
|
||||||
|
await page.locator('#next').click();
|
||||||
|
await expect(page.locator('#status')).toHaveText('Page 2 / 6');
|
||||||
|
await page.waitForTimeout(700);
|
||||||
|
|
||||||
|
await expect(page.locator('#book')).toHaveScreenshot('minimal-book-page-2.png');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('minimal demo keeps turn geometry aligned in a compact viewport', async ({ page }) => {
|
||||||
|
await page.setViewportSize({ width: 600, height: 720 });
|
||||||
|
await page.goto(`${baseUrl}/demos/minimal/index.html`);
|
||||||
|
await page.waitForFunction(() => window.jQuery && window.jQuery.fn.jquery === '4.0.0' && typeof window.jQuery.fn.turn === 'function');
|
||||||
|
|
||||||
|
const metrics = await page.evaluate(() => {
|
||||||
|
const book = document.querySelector('#book').getBoundingClientRect();
|
||||||
|
const wrapper = document.querySelector('.turn-page-wrapper').getBoundingClientRect();
|
||||||
|
const size = $('#book').turn('size');
|
||||||
|
|
||||||
|
return {
|
||||||
|
book: { width: Math.round(book.width), height: Math.round(book.height) },
|
||||||
|
wrapper: { width: Math.round(wrapper.width), height: Math.round(wrapper.height) },
|
||||||
|
size
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(metrics.size).toEqual(metrics.book);
|
||||||
|
expect(metrics.wrapper.height).toBe(metrics.book.height);
|
||||||
|
expect(metrics.wrapper.width).toBe(metrics.book.width / 2);
|
||||||
|
await expect(page.locator('#book')).toHaveScreenshot('minimal-book-compact-page-1.png');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('minimal demo keeps page measurements aligned during a page turn', async ({ page }) => {
|
||||||
|
await page.goto(`${baseUrl}/demos/minimal/index.html`);
|
||||||
|
await page.waitForFunction(() => window.jQuery && window.jQuery.fn.jquery === '4.0.0' && typeof window.jQuery.fn.turn === 'function');
|
||||||
|
|
||||||
|
await page.locator('#next').click();
|
||||||
|
await page.waitForTimeout(700);
|
||||||
|
await page.locator('#next').click();
|
||||||
|
await page.waitForTimeout(700);
|
||||||
|
await expect(page.locator('#status')).toHaveText('Page 4 / 6');
|
||||||
|
|
||||||
|
await page.locator('#next').click();
|
||||||
|
await page.waitForTimeout(160);
|
||||||
|
|
||||||
|
const metrics = await page.evaluate(() => {
|
||||||
|
const book = document.querySelector('#book').getBoundingClientRect();
|
||||||
|
const pageWidth = Math.round(book.width / 2);
|
||||||
|
const pageHeight = Math.round(book.height);
|
||||||
|
|
||||||
|
const pages = [...document.querySelectorAll('.turn-page')]
|
||||||
|
.map(element => {
|
||||||
|
const rect = element.getBoundingClientRect();
|
||||||
|
|
||||||
|
return {
|
||||||
|
page: element.className,
|
||||||
|
width: Math.round(rect.width),
|
||||||
|
height: Math.round(rect.height),
|
||||||
|
jqueryWidth: Math.round($(element).width()),
|
||||||
|
jqueryHeight: Math.round($(element).height())
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.filter(item => item.width || item.height);
|
||||||
|
|
||||||
|
return { pageWidth, pageHeight, pages };
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const item of metrics.pages) {
|
||||||
|
expect(item.width, item.page).toBe(metrics.pageWidth);
|
||||||
|
expect(item.height, item.page).toBe(metrics.pageHeight);
|
||||||
|
expect(item.jqueryWidth, item.page).toBe(metrics.pageWidth);
|
||||||
|
expect(item.jqueryHeight, item.page).toBe(metrics.pageHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
await expect(page.locator('#book')).toHaveScreenshot('minimal-book-turning-page-4.png');
|
||||||
|
});
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 18 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 36 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
7
vitest.config.mjs
Normal file
7
vitest.config.mjs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import { defineConfig } from 'vitest/config';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
test: {
|
||||||
|
include: ['tests/unit/**/*.test.js']
|
||||||
|
}
|
||||||
|
});
|
||||||
Loading…
x
Reference in New Issue
Block a user