mirror of
https://github.com/PeWu/topola-viewer.git
synced 2026-05-26 15:16:14 +00:00
241 lines
6.0 KiB
TypeScript
241 lines
6.0 KiB
TypeScript
import {expect, test} from '@playwright/test';
|
|
import dedent from 'dedent';
|
|
import * as fs from 'fs';
|
|
import {mockGedcomResponse, setupHermeticEnvironment} from './helpers';
|
|
|
|
test.describe('Details panel visual validation @visual', () => {
|
|
test.beforeEach(async ({context}) => {
|
|
await setupHermeticEnvironment(context);
|
|
});
|
|
|
|
test('Complex Names Test', async ({page, context}) => {
|
|
const complexNameGedcom = dedent`
|
|
0 HEAD
|
|
1 GEDC
|
|
2 VERS 5.5.1
|
|
2 FORM Lineage-Linked
|
|
1 CHAR UTF-8
|
|
0 @I1@ INDI
|
|
1 NAME Dr. Bonifacy "Boni" /Gibbs/ III
|
|
2 NPFX Dr.
|
|
2 GIVN Bonifacy
|
|
2 NICK Boni
|
|
2 SURN Gibbs
|
|
2 NSFX III
|
|
2 _RUFNAME Bonifacy
|
|
1 SEX M
|
|
1 FAMS @F1@
|
|
0 @F1@ FAM
|
|
1 HUSB @I1@
|
|
0 TRLR
|
|
`;
|
|
|
|
await mockGedcomResponse(context, complexNameGedcom);
|
|
|
|
await page.goto('/#/view?url=https://example.org/family.ged');
|
|
const sidebar = page.locator('#sidebar');
|
|
await sidebar.waitFor();
|
|
await expect(sidebar).toHaveScreenshot('details-complex-name.png');
|
|
});
|
|
|
|
test('Image / Photo Rendering Test', async ({page, context}) => {
|
|
const photoGedcom = dedent`
|
|
0 HEAD
|
|
1 GEDC
|
|
2 VERS 5.5.1
|
|
2 FORM Lineage-Linked
|
|
1 CHAR UTF-8
|
|
0 @I1@ INDI
|
|
1 NAME Bonifacy /Gibbs/
|
|
1 SEX M
|
|
1 FAMS @F1@
|
|
1 OBJE @O1@
|
|
0 @O1@ OBJE
|
|
1 FILE http://example.org/photos/I1.jpg
|
|
2 FORM jpeg
|
|
0 @F1@ FAM
|
|
1 HUSB @I1@
|
|
0 TRLR
|
|
`;
|
|
|
|
await mockGedcomResponse(context, photoGedcom);
|
|
|
|
await context.route('**/photos/I1.jpg', async (route) => {
|
|
const imageBuffer = fs.readFileSync(
|
|
'docker/examples/photos/photos/I1.jpg',
|
|
);
|
|
await route.fulfill({
|
|
status: 200,
|
|
contentType: 'image/jpeg',
|
|
body: imageBuffer,
|
|
});
|
|
});
|
|
|
|
await page.goto('/#/view?url=https://example.org/family.ged');
|
|
const sidebar = page.locator('#sidebar');
|
|
await sidebar.waitFor();
|
|
|
|
// Wait for image loading to complete
|
|
const img = sidebar.locator('img').first();
|
|
await img.waitFor({state: 'visible'});
|
|
await img.evaluate((image) => {
|
|
return new Promise((resolve, reject) => {
|
|
if ((image as HTMLImageElement).complete) resolve(true);
|
|
image.addEventListener('load', () => resolve(true));
|
|
image.addEventListener('error', () =>
|
|
reject(new Error('Image failed to load')),
|
|
);
|
|
});
|
|
});
|
|
|
|
await expect(sidebar).toHaveScreenshot('details-photo-render.png');
|
|
});
|
|
|
|
test('Custom Facts & Citations Test', async ({page, context}) => {
|
|
const customFactsGedcom = dedent`
|
|
0 HEAD
|
|
1 GEDC
|
|
2 VERS 5.5.1
|
|
2 FORM Lineage-Linked
|
|
1 CHAR UTF-8
|
|
0 @I1@ INDI
|
|
1 NAME Bonifacy /Gibbs/
|
|
1 SEX M
|
|
1 FAMS @F1@
|
|
1 FACT Custom fact data
|
|
2 TYPE Custom Fact Type
|
|
2 SOUR @S1@
|
|
3 PAGE 42
|
|
3 DATA
|
|
4 DATE 12 JAN 1850
|
|
2 NOTE This is a note nested under a custom fact.
|
|
1 BIRT
|
|
2 DATE 1 JAN 1800
|
|
2 PLAC Paris, France
|
|
2 SOUR @S1@
|
|
3 PAGE 10
|
|
2 NOTE Birth event note.
|
|
1 DEAT
|
|
2 DATE 31 DEC 1880
|
|
2 PLAC London, UK
|
|
1 NOTE This is a top-level note for the individual.
|
|
0 @S1@ SOUR
|
|
1 TITL Great Genealogy Book
|
|
1 AUTH John Doe
|
|
1 PUBL London Publishing, 1890
|
|
0 @F1@ FAM
|
|
1 HUSB @I1@
|
|
0 TRLR
|
|
`;
|
|
|
|
await mockGedcomResponse(context, customFactsGedcom);
|
|
|
|
await page.goto('/#/view?url=https://example.org/family.ged');
|
|
const sidebar = page.locator('#sidebar');
|
|
await sidebar.waitFor();
|
|
await expect(sidebar).toHaveScreenshot('details-events-sources.png');
|
|
});
|
|
|
|
test('Immediate Family Rendering Test', async ({page, context}) => {
|
|
const immediateFamilyGedcom = dedent`
|
|
0 HEAD
|
|
1 GEDC
|
|
2 VERS 5.5.1
|
|
2 FORM Lineage-Linked
|
|
1 CHAR UTF-8
|
|
0 @I1@ INDI
|
|
1 NAME Focus /Person/
|
|
1 SEX M
|
|
1 FAMC @F1@
|
|
1 FAMS @F2@
|
|
1 FAMS @F3@
|
|
0 @I2@ INDI
|
|
1 NAME Father /Person/
|
|
1 SEX M
|
|
1 FAMS @F1@
|
|
0 @I3@ INDI
|
|
1 NAME Mother /Person/
|
|
1 SEX F
|
|
1 FAMS @F1@
|
|
0 @I4@ INDI
|
|
1 NAME Spouse /Person/
|
|
1 SEX F
|
|
1 FAMS @F2@
|
|
0 @I5@ INDI
|
|
1 NAME Older /Child/
|
|
1 SEX M
|
|
1 BIRT
|
|
2 DATE 1 JAN 2000
|
|
1 FAMC @F2@
|
|
0 @I6@ INDI
|
|
1 NAME Younger /Child/
|
|
1 SEX F
|
|
1 BIRT
|
|
2 DATE 1 JAN 2005
|
|
1 FAMC @F2@
|
|
0 @I7@ INDI
|
|
1 NAME Half /Child/
|
|
1 SEX M
|
|
1 BIRT
|
|
2 DATE 1 JAN 2010
|
|
1 FAMC @F3@
|
|
0 @F1@ FAM
|
|
1 HUSB @I2@
|
|
1 WIFE @I3@
|
|
1 CHIL @I1@
|
|
0 @F2@ FAM
|
|
1 HUSB @I1@
|
|
1 WIFE @I4@
|
|
1 CHIL @I5@
|
|
1 CHIL @I6@
|
|
0 @F3@ FAM
|
|
1 HUSB @I1@
|
|
1 CHIL @I7@
|
|
0 TRLR
|
|
`;
|
|
|
|
await mockGedcomResponse(context, immediateFamilyGedcom);
|
|
|
|
await page.goto('/#/view?url=https://example.org/family.ged');
|
|
const sidebar = page.locator('#sidebar');
|
|
await sidebar.waitFor();
|
|
await expect(sidebar).toHaveScreenshot('details-immediate-family.png');
|
|
});
|
|
|
|
test('Media Fallback Rendering Test', async ({page, context}) => {
|
|
const fallbackGedcom = dedent`
|
|
0 HEAD
|
|
1 GEDC
|
|
2 VERS 5.5.1
|
|
2 FORM Lineage-Linked
|
|
1 CHAR UTF-8
|
|
0 @I1@ INDI
|
|
1 NAME Bonifacy /Gibbs/
|
|
1 SEX M
|
|
1 FAMS @F1@
|
|
1 OBJE @O1@
|
|
0 @O1@ OBJE
|
|
1 FILE photos/not_uploaded_image.jpg
|
|
2 FORM jpeg
|
|
2 TITL A Not Uploaded Image
|
|
0 @F1@ FAM
|
|
1 HUSB @I1@
|
|
0 TRLR
|
|
`;
|
|
|
|
await mockGedcomResponse(context, fallbackGedcom);
|
|
|
|
await page.goto('/#/view?url=https://example.org/family.ged');
|
|
const sidebar = page.locator('#sidebar');
|
|
await sidebar.waitFor();
|
|
|
|
// Verify fallback placeholder text is present
|
|
await expect(sidebar.getByText('File not uploaded').first()).toBeVisible();
|
|
await expect(
|
|
sidebar.getByText('A Not Uploaded Image').first(),
|
|
).toBeVisible();
|
|
|
|
await expect(sidebar).toHaveScreenshot('details-media-fallback.png');
|
|
});
|
|
});
|