test(item-sliding): add test for side issue with CDN (#30469)

Adds test for https://github.com/ionic-team/ionic-framework/pull/29845

Must be merged after the fix in that PR is released. The test will fail
while using the older version of the CDN.

---------

Co-authored-by: Brandy Smith <6577830+brandyscarney@users.noreply.github.com>
This commit is contained in:
Brandy Smith
2025-07-08 16:18:23 -04:00
committed by GitHub
parent 498f7c7ab2
commit 73f7b3f839
3 changed files with 111 additions and 2 deletions

View File

@ -1,6 +1,9 @@
import { expect } from '@playwright/test'; import { expect } from '@playwright/test';
import { configs, test } from '@utils/test/playwright'; import { configs, test } from '@utils/test/playwright';
/**
* This behavior does not vary across modes/directions
*/
configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => { configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => {
test.describe(title('item-sliding: async'), () => { test.describe(title('item-sliding: async'), () => {
test.beforeEach(async ({ page }) => { test.beforeEach(async ({ page }) => {
@ -35,5 +38,85 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>
await expect(itemSlidingEl).toHaveClass(/item-sliding-active-slide/); await expect(itemSlidingEl).toHaveClass(/item-sliding-active-slide/);
}); });
// NOTE: This test uses the CDN version of Ionic.
// If this test fails, it is likely due to a regression in the published package.
test('should not throw errors when adding multiple items with side="end" using the Ionic CDN', async ({
page,
}, testInfo) => {
testInfo.annotations.push({
type: 'issue',
description: 'https://github.com/ionic-team/ionic-framework/issues/29499',
});
const errors: string[] = [];
page.on('console', (msg) => {
if (msg.type() === 'error') {
errors.push(msg.text());
}
});
page.on('pageerror', (error) => {
errors.push(error.message);
});
// This issue only happens when using a CDN version of Ionic
// so we need to use the CDN by passing the `importIonicFromCDN` option
// to setContent.
await page.setContent(
`
<ion-header>
<ion-toolbar>
<ion-title>Item Sliding</ion-title>
<ion-buttons slot="end">
<ion-button id="addItem" onclick="addItem()">ADD ITEM</ion-button>
</ion-buttons>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-list id="list"></ion-list>
</ion-content>
<script>
let itemList = [];
function generateItem() {
const currentItem = itemList.length + 1;
const item = \`
<ion-item-sliding>
<ion-item>
<ion-label>Sliding Item \${currentItem}</ion-label>
</ion-item>
<ion-item-options side="end">
<ion-item-option>Delete</ion-item-option>
</ion-item-options>
</ion-item-sliding>
\`;
itemList.push(item);
return item;
}
function addItem() {
const list = document.getElementById('list');
list.innerHTML += generateItem();
const currentItem = itemList.length;
}
</script>
`,
{ ...config, importIonicFromCDN: true }
);
// Click the button enough times to reproduce the issue
const addButton = page.locator('#addItem');
await addButton.click();
await addButton.click();
await addButton.click();
await page.waitForChanges();
// Check that the items have been added
const items = page.locator('ion-item-sliding');
expect(await items.count()).toBe(3);
// Check that no errors have been logged
expect(errors.length).toBe(0);
});
}); });
}); });

View File

@ -33,6 +33,26 @@ export const setContent = async (page: Page, html: string, testInfo: TestInfo, o
const baseUrl = process.env.PLAYWRIGHT_TEST_BASE_URL; const baseUrl = process.env.PLAYWRIGHT_TEST_BASE_URL;
// The Ionic bundle is included locally by default unless the test
// config passes in the importIonicFromCDN option. This is useful
// when testing with the CDN version of Ionic.
let ionicCSSImports = `
<link href="${baseUrl}/css/ionic.bundle.css" rel="stylesheet" />
`;
let ionicJSImports = `
<script type="module" src="${baseUrl}/dist/ionic/ionic.esm.js"></script>
`;
if (options?.importIonicFromCDN) {
ionicCSSImports = `
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ionic/core/css/ionic.bundle.css" />
`;
ionicJSImports = `
<script type="module" src="https://cdn.jsdelivr.net/npm/@ionic/core/dist/ionic/ionic.esm.js"></script>
<script nomodule src="https://cdn.jsdelivr.net/npm/@ionic/core/dist/ionic/ionic.js"></script>
`;
}
const output = ` const output = `
<!DOCTYPE html> <!DOCTYPE html>
<html dir="${direction}" lang="en"> <html dir="${direction}" lang="en">
@ -40,11 +60,11 @@ export const setContent = async (page: Page, html: string, testInfo: TestInfo, o
<title>Ionic Playwright Test</title> <title>Ionic Playwright Test</title>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0" />
<link href="${baseUrl}/css/ionic.bundle.css" rel="stylesheet" /> ${ionicCSSImports}
<link href="${baseUrl}/scripts/testing/styles.css" rel="stylesheet" /> <link href="${baseUrl}/scripts/testing/styles.css" rel="stylesheet" />
${palette !== 'light' ? `<link href="${baseUrl}/css/palettes/${palette}.always.css" rel="stylesheet" />` : ''} ${palette !== 'light' ? `<link href="${baseUrl}/css/palettes/${palette}.always.css" rel="stylesheet" />` : ''}
<script src="${baseUrl}/scripts/testing/scripts.js"></script> <script src="${baseUrl}/scripts/testing/scripts.js"></script>
<script type="module" src="${baseUrl}/dist/ionic/ionic.esm.js"></script> ${ionicJSImports}
<script> <script>
window.Ionic = { window.Ionic = {
config: { config: {

View File

@ -31,6 +31,12 @@ interface PageOptions {
* - `'commit'` - consider operation to be finished when network response is received and the document started loading. * - `'commit'` - consider operation to be finished when network response is received and the document started loading.
*/ */
waitUntil?: 'load' | 'domcontentloaded' | 'networkidle' | 'commit'; waitUntil?: 'load' | 'domcontentloaded' | 'networkidle' | 'commit';
/**
* If true, the default Ionic imports will be included
* via the CDN instead of the local bundle.
*/
importIonicFromCDN?: boolean;
} }
export interface E2EPage extends Page { export interface E2EPage extends Page {