Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Jul 8, 2025
83 changes: 83 additions & 0 deletions core/src/components/item-sliding/test/async/item-sliding.e2e.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { expect } from '@playwright/test';
import { configs, test } from '@utils/test/playwright';

/**
* This behavior does not vary across modes/directions
*/
configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => {
test.describe(title('item-sliding: async'), () => {
test.beforeEach(async ({ page }) => {
Expand Down Expand Up @@ -35,5 +38,85 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>

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);
});
});
});
24 changes: 22 additions & 2 deletions core/src/utils/test/playwright/page/utils/set-content.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,18 +33,38 @@ export const setContent = async (page: Page, html: string, testInfo: TestInfo, o

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 = `
<!DOCTYPE html>
<html dir="${direction}" lang="en">
<head>
<title>Ionic Playwright Test</title>
<meta charset="UTF-8" />
<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" />
${palette !== 'light' ? `<link href="${baseUrl}/css/palettes/${palette}.always.css" rel="stylesheet" />` : ''}
<script src="${baseUrl}/scripts/testing/scripts.js"></script>
<script type="module" src="${baseUrl}/dist/ionic/ionic.esm.js"></script>
${ionicJSImports}
<script>
window.Ionic = {
config: {
Expand Down
6 changes: 6 additions & 0 deletions core/src/utils/test/playwright/playwright-declarations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ interface PageOptions {
* - `'commit'` - consider operation to be finished when network response is received and the document started loading.
*/
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 {
Expand Down
Loading