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
2 changes: 2 additions & 0 deletions src/tests/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
export * from './suites/seo.test';
export * from './suites/performance.test';
export * from './suites/socialMedia.test';
export * from './suites/lightbox.test';
export * from './suites/list.test';

43 changes: 43 additions & 0 deletions src/tests/suites/lightbox.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import {PlaywrightTest} from "../types.js";
import type {Page} from "playwright/test";

export async function TestLightbox_openCloseViaPswp({page, playwrightTest, gallerySelector = '.Gallery', slideSelector = 'swiper-slide', openTimeout = 5000, closeTimeout = 10000}: {
page: Page,
playwrightTest: PlaywrightTest,
gallerySelector?: string,
slideSelector?: string,
openTimeout?: number,
closeTimeout?: number,
}) {
const {expect} = playwrightTest;

await playwrightTest.test.step('lightbox should open on slide click', async () => {
const activeSlide = page.locator(`${gallerySelector} ${slideSelector}`).first();
await activeSlide.scrollIntoViewIfNeeded();
await activeSlide.click();
await page.waitForSelector('.pswp--open', {state: 'visible', timeout: openTimeout});
});

await playwrightTest.test.step('lightbox should be open and visible', async () => {
await expect(page.locator('.pswp--open')).toBeVisible();
});

await playwrightTest.test.step('lightbox should have close button', async () => {
await expect(page.locator('.pswp--open .pswp__button--close')).toBeVisible();
});

await playwrightTest.test.step('lightbox should have an image', async () => {
await expect(page.locator('.pswp--open .pswp__img').first()).toBeVisible();
});

await playwrightTest.test.step('lightbox should close after clicking close button', async () => {
await page.waitForTimeout(1000);
await page.evaluate(() => {
const pswpEl = document.querySelector('.pswp');
const closeBtn = pswpEl?.querySelector('.pswp__button--close') as HTMLElement;
closeBtn?.click();
});
Comment on lines +34 to +39
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The close step uses a fixed waitForTimeout(1000) and page.evaluate() DOM-click to close the lightbox. This is prone to flakiness and bypasses Playwright’s auto-waiting/actionability checks. Prefer clicking the close button via a locator (the test already asserts it exists) and waiting for .pswp--open to detach/hidden without an arbitrary sleep.

Suggested change
await page.waitForTimeout(1000);
await page.evaluate(() => {
const pswpEl = document.querySelector('.pswp');
const closeBtn = pswpEl?.querySelector('.pswp__button--close') as HTMLElement;
closeBtn?.click();
});
const closeButton = page.locator('.pswp--open .pswp__button--close');
await closeButton.click();
await page.waitForSelector('.pswp--open', {state: 'hidden', timeout: closeTimeout});

Copilot uses AI. Check for mistakes.
await expect(page.locator('.pswp--open')).not.toBeVisible({timeout: closeTimeout});
});
}

73 changes: 73 additions & 0 deletions src/tests/suites/list.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import {PlaywrightTest} from "../types.js";
import type {Page} from "playwright/test";
import {TestsHelper_elementNotEmpty, TestsHelper_elementExists} from "../../helpers/TestsHelper";

export async function TestList_infiniteScrollPagination({page, playwrightTest, listSelector = '.gridWidgetTypeGenericList', itemSelector = '.Item', buttonSelector = '.infiniteScrollButton', loadTimeout = 10000}: {
page: Page,
playwrightTest: PlaywrightTest,
listSelector?: string,
itemSelector?: string,
buttonSelector?: string,
loadTimeout?: number,
}) {
const {expect} = playwrightTest;
const itemsFullSelector = `${listSelector} ${itemSelector}`;
let itemsBeforePagination = 0;

await playwrightTest.test.step('items should exist before pagination', async () => {
itemsBeforePagination = await page.locator(itemsFullSelector).count();
expect(itemsBeforePagination, 'Items should exist before pagination').toBeGreaterThan(0);
});

await playwrightTest.test.step('pagination button should be visible', async () => {
const paginationButton = page.locator(buttonSelector);
await expect(paginationButton, 'Pagination button should be visible').toBeVisible();
});

await playwrightTest.test.step('clicking pagination button should load more items', async () => {
const paginationButton = page.locator(buttonSelector);
await paginationButton.scrollIntoViewIfNeeded();
await paginationButton.click();
Comment on lines +22 to +30
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

paginationButton is located via page.locator(buttonSelector) without scoping it to the list container. If the page has more than one GenericList (or another element matching .infiniteScrollButton), this can click the wrong button and make the test non-deterministic. Consider scoping the locator (and related waits) to the listSelector container (e.g., locate the list first, then locate the button within it).

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot apply changes based on this feedback

await page.waitForFunction(
({selector, prevCount}) => document.querySelectorAll(selector).length > prevCount,
{selector: itemsFullSelector, prevCount: itemsBeforePagination},
{timeout: loadTimeout}
);
const itemsAfterPagination = await page.locator(itemsFullSelector).count();
expect(itemsAfterPagination, `Items count should increase after pagination (was ${itemsBeforePagination})`).toBeGreaterThan(itemsBeforePagination);
});

await playwrightTest.test.step('new items should have title', async () => {
await TestsHelper_elementNotEmpty({
page,
playwrightTest,
description: "New items should have titles",
selector: `${itemsFullSelector} >> nth=${itemsBeforePagination} >> .Title`
});
});

await playwrightTest.test.step('new items should have image', async () => {
await TestsHelper_elementExists({
page,
playwrightTest,
description: "New items should have images",
selector: `${itemsFullSelector} >> nth=${itemsBeforePagination} >> .Image img`
});
});

await playwrightTest.test.step('new items should have working links', async () => {
const firstNewItem = page.locator(itemsFullSelector).nth(itemsBeforePagination);
const newItemLink = firstNewItem.locator('a').first();
const href = await newItemLink.getAttribute('href');
expect(href, 'New item link should have href').toBeTruthy();
expect(href, 'New item link href should not be empty').not.toBe('');
});

await playwrightTest.test.step('new items should not duplicate existing items', async () => {
const firstItemTitle = await page.locator(itemsFullSelector).first().locator('.Title').textContent();
const firstNewItem = page.locator(itemsFullSelector).nth(itemsBeforePagination);
const firstNewItemTitle = await firstNewItem.locator('.Title').textContent();
expect(firstNewItemTitle, 'New items should not duplicate existing items').not.toBe(firstItemTitle);
Comment on lines +66 to +70
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The duplication check compares only the first item title vs. the first newly loaded item title. Different stories can legitimately share the same title, so this assertion can produce false failures even when pagination works correctly. A more reliable approach is to compare a unique attribute (e.g., href/URL) and assert that at least one newly loaded item has an href not present in the pre-pagination set.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot apply changes based on this feedback

});
}

2 changes: 2 additions & 0 deletions testDist/tests/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
export * from './suites/seo.test';
export * from './suites/performance.test';
export * from './suites/socialMedia.test';
export * from './suites/lightbox.test';
export * from './suites/list.test';
4 changes: 3 additions & 1 deletion testDist/tests/index.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions testDist/tests/suites/lightbox.test.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { PlaywrightTest } from "../types";
import type { Page } from "playwright/test";
export declare function TestLightbox_openCloseViaPswp({ page, playwrightTest, gallerySelector, slideSelector, openTimeout, closeTimeout }: {
page: Page;
playwrightTest: PlaywrightTest;
gallerySelector?: string;
slideSelector?: string;
openTimeout?: number;
closeTimeout?: number;
}): Promise<void>;

32 changes: 32 additions & 0 deletions testDist/tests/suites/lightbox.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.TestLightbox_openCloseViaPswp = TestLightbox_openCloseViaPswp;
async function TestLightbox_openCloseViaPswp({ page, playwrightTest, gallerySelector = '.Gallery', slideSelector = 'swiper-slide', openTimeout = 5000, closeTimeout = 10000 }) {
const { expect } = playwrightTest;
await playwrightTest.test.step('lightbox should open on slide click', async () => {
const activeSlide = page.locator(`${gallerySelector} ${slideSelector}`).first();
await activeSlide.scrollIntoViewIfNeeded();
await activeSlide.click();
await page.waitForSelector('.pswp--open', { state: 'visible', timeout: openTimeout });
});
await playwrightTest.test.step('lightbox should be open and visible', async () => {
await expect(page.locator('.pswp--open')).toBeVisible();
});
await playwrightTest.test.step('lightbox should have close button', async () => {
await expect(page.locator('.pswp--open .pswp__button--close')).toBeVisible();
});
await playwrightTest.test.step('lightbox should have an image', async () => {
await expect(page.locator('.pswp--open .pswp__img').first()).toBeVisible();
});
await playwrightTest.test.step('lightbox should close after clicking close button', async () => {
await page.waitForTimeout(1000);
await page.evaluate(() => {
const pswpEl = document.querySelector('.pswp');
const closeBtn = pswpEl?.querySelector('.pswp__button--close');
closeBtn?.click();
});
await expect(page.locator('.pswp--open')).not.toBeVisible({ timeout: closeTimeout });
});
}
//# sourceMappingURL=lightbox.test.js.map

11 changes: 11 additions & 0 deletions testDist/tests/suites/list.test.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { PlaywrightTest } from "../types";
import type { Page } from "playwright/test";
export declare function TestList_infiniteScrollPagination({ page, playwrightTest, listSelector, itemSelector, buttonSelector, loadTimeout }: {
page: Page;
playwrightTest: PlaywrightTest;
listSelector?: string;
itemSelector?: string;
buttonSelector?: string;
loadTimeout?: number;
}): Promise<void>;

56 changes: 56 additions & 0 deletions testDist/tests/suites/list.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.TestList_infiniteScrollPagination = TestList_infiniteScrollPagination;
const TestsHelper_1 = require("../../helpers/TestsHelper");
async function TestList_infiniteScrollPagination({ page, playwrightTest, listSelector = '.gridWidgetTypeGenericList', itemSelector = '.Item', buttonSelector = '.infiniteScrollButton', loadTimeout = 10000 }) {
const { expect } = playwrightTest;
const itemsFullSelector = `${listSelector} ${itemSelector}`;
let itemsBeforePagination = 0;
await playwrightTest.test.step('items should exist before pagination', async () => {
itemsBeforePagination = await page.locator(itemsFullSelector).count();
expect(itemsBeforePagination, 'Items should exist before pagination').toBeGreaterThan(0);
});
await playwrightTest.test.step('pagination button should be visible', async () => {
const paginationButton = page.locator(buttonSelector);
await expect(paginationButton, 'Pagination button should be visible').toBeVisible();
});
await playwrightTest.test.step('clicking pagination button should load more items', async () => {
const paginationButton = page.locator(buttonSelector);
await paginationButton.scrollIntoViewIfNeeded();
await paginationButton.click();
await page.waitForFunction(({ selector, prevCount }) => document.querySelectorAll(selector).length > prevCount, { selector: itemsFullSelector, prevCount: itemsBeforePagination }, { timeout: loadTimeout });
const itemsAfterPagination = await page.locator(itemsFullSelector).count();
expect(itemsAfterPagination, `Items count should increase after pagination (was ${itemsBeforePagination})`).toBeGreaterThan(itemsBeforePagination);
});
await playwrightTest.test.step('new items should have title', async () => {
await (0, TestsHelper_1.TestsHelper_elementNotEmpty)({
page,
playwrightTest,
description: "New items should have titles",
selector: `${itemsFullSelector} >> nth=${itemsBeforePagination} >> .Title`
});
});
await playwrightTest.test.step('new items should have image', async () => {
await (0, TestsHelper_1.TestsHelper_elementExists)({
page,
playwrightTest,
description: "New items should have images",
selector: `${itemsFullSelector} >> nth=${itemsBeforePagination} >> .Image img`
});
});
await playwrightTest.test.step('new items should have working links', async () => {
const firstNewItem = page.locator(itemsFullSelector).nth(itemsBeforePagination);
const newItemLink = firstNewItem.locator('a').first();
const href = await newItemLink.getAttribute('href');
expect(href, 'New item link should have href').toBeTruthy();
expect(href, 'New item link href should not be empty').not.toBe('');
});
await playwrightTest.test.step('new items should not duplicate existing items', async () => {
const firstItemTitle = await page.locator(itemsFullSelector).first().locator('.Title').textContent();
const firstNewItem = page.locator(itemsFullSelector).nth(itemsBeforePagination);
const firstNewItemTitle = await firstNewItem.locator('.Title').textContent();
expect(firstNewItemTitle, 'New items should not duplicate existing items').not.toBe(firstItemTitle);
});
}
//# sourceMappingURL=list.test.js.map

Loading