diff --git a/core/src/components/router/test/basic/e2e.ts b/core/src/components/router/test/basic/e2e.ts
deleted file mode 100644
index d224936f06..0000000000
--- a/core/src/components/router/test/basic/e2e.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-import { newE2EPage } from '@stencil/core/testing';
-
-test('router: basic', async () => {
- const page = await newE2EPage({
- url: '/src/components/router/test/basic?ionic:_testing=true',
- });
-
- const compare = await page.compareScreenshot();
- expect(compare).toMatchScreenshot();
-});
diff --git a/core/src/components/router/test/basic/index.html b/core/src/components/router/test/basic/index.html
index e34caa59e1..406adb95f4 100644
--- a/core/src/components/router/test/basic/index.html
+++ b/core/src/components/router/test/basic/index.html
@@ -2,7 +2,7 @@
- Nav
+ Router
{
- const page = await newE2EPage({
- url: '/src/components/router/test/basic#/redirect-to-three?ionic:_testing=true',
- });
-
- await page.waitForChanges();
-
- const url = page.url();
- expect(url).toContain('#/three?has_query_string=true');
-});
diff --git a/core/src/components/router/test/basic/router-push/e2e.ts b/core/src/components/router/test/basic/router-push/e2e.ts
deleted file mode 100644
index 6387da2eb3..0000000000
--- a/core/src/components/router/test/basic/router-push/e2e.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-import { newE2EPage } from '@stencil/core/testing';
-
-test('push should support relative path', async () => {
- const page = await newE2EPage({
- url: '/src/components/router/test/basic#/two/three/hola?ionic:_testing=true',
- });
- await page.waitForChanges();
-
- const backButton = await page.$('#btn-rel');
- await backButton?.click();
- await page.waitForChanges();
-
- const url = page.url();
- expect(url).toContain('#/two/three/relative?param=1');
-});
-
-test('push should support absolute path', async () => {
- const page = await newE2EPage({
- url: '/src/components/router/test/basic#/two/three/hola?ionic:_testing=true',
- });
- await page.waitForChanges();
-
- const backButton = await page.$('#btn-abs');
- await backButton?.click();
- await page.waitForChanges();
-
- const url = page.url();
- expect(url).toContain('#/two/three/absolute');
-});
diff --git a/core/src/components/router/test/basic/router.e2e.ts b/core/src/components/router/test/basic/router.e2e.ts
new file mode 100644
index 0000000000..e5d87cabf7
--- /dev/null
+++ b/core/src/components/router/test/basic/router.e2e.ts
@@ -0,0 +1,100 @@
+import { expect } from '@playwright/test';
+import { test } from '@utils/test/playwright';
+
+test.describe('router: redirect', () => {
+ test.beforeEach(({ skip }) => {
+ skip.mode('md');
+ skip.rtl();
+ });
+
+ test('contains query parameters after redirect', async ({ page }) => {
+ await page.goto(`/src/components/router/test/basic#/redirect-to-three`);
+
+ expect(page.url()).toContain('#/three?has_query_string=true');
+ });
+});
+
+test.describe('router: push', () => {
+ test.beforeEach(({ skip }) => {
+ skip.mode('md');
+ skip.rtl();
+ });
+
+ test('should support relative path', async ({ page }) => {
+ await page.goto(`/src/components/router/test/basic#/two/three/hola`);
+ await page.click('#btn-rel');
+
+ expect(page.url()).toContain('#/two/three/relative?param=1');
+ });
+
+ test('should support absolute path', async ({ page }) => {
+ await page.goto(`/src/components/router/test/basic#/two/three/hola`);
+ await page.click('#btn-abs');
+
+ expect(page.url()).toContain('#/two/three/absolute');
+ });
+});
+
+test.describe('router: tabs', () => {
+ test.beforeEach(({ skip }) => {
+ skip.mode('md');
+ skip.rtl();
+ });
+
+ test('should activate the initial tab', async ({ page }) => {
+ await page.goto(`/src/components/router/test/basic`);
+
+ const tabOne = page.locator('tab-one');
+
+ await expect(tabOne).toBeVisible();
+
+ expect(page.url()).toContain('/basic?');
+ });
+
+ /**
+ * Selects the Schedule (tab two) tab and verifies that both the
+ * page is visible and the URL is correct.
+ */
+ test('selecting a tab routes to the tab page', async ({ page }) => {
+ await page.goto(`/src/components/router/test/basic`);
+
+ const tabOne = page.locator('tab-one');
+ const tabTwo = page.locator('tab-two');
+
+ await page.click('#tab-button-tab-two');
+
+ await expect(tabOne).toBeHidden();
+ await expect(tabTwo).toBeVisible();
+
+ expect(page.url()).toContain('#/two');
+ });
+
+ test('should navigate to a nested page within a tab', async ({ page }) => {
+ await page.goto('/src/components/router/test/basic#/two');
+
+ const tabTwo = page.locator('tab-two');
+ const pageOne = page.locator('page-one');
+
+ await expect(tabTwo).toBeVisible();
+ await expect(pageOne).toBeVisible();
+
+ await page.click('text=Go to page 2');
+
+ const pageTwo = page.locator('page-two');
+
+ await expect(pageTwo).toBeVisible();
+ await expect(pageOne).toBeHidden();
+
+ await expect(page.url()).toContain('#/two/second-page');
+ });
+
+ test('navigating directly to a sub page should activate the page', async ({ page }) => {
+ await page.goto('/src/components/router/test/basic#/two/second-page');
+
+ const tabTwo = page.locator('tab-two');
+ const pageTwo = page.locator('page-two');
+
+ await expect(tabTwo).toBeVisible();
+ await expect(pageTwo).toBeVisible();
+ });
+});
diff --git a/core/src/components/router/test/guards/e2e.ts b/core/src/components/router/test/guards/e2e.ts
deleted file mode 100644
index 94ca5965c9..0000000000
--- a/core/src/components/router/test/guards/e2e.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-import { newE2EPage } from '@stencil/core/testing';
-
-test('router: guards - guards should be run on initial load', async () => {
- const page = await newE2EPage({
- url: '/src/components/router/test/guards#/guard-initial-page?ionic:_testing=true',
- });
-
- await page.waitForChanges();
-
- await checkUrl(page, '#/child/1');
-});
-
-const checkUrl = async (page, url: string) => {
- const getUrl = await page.url();
- expect(getUrl).toContain(url);
-};
diff --git a/core/src/components/router/test/guards/href/e2e.ts b/core/src/components/router/test/guards/href/e2e.ts
deleted file mode 100644
index 0d12d447e8..0000000000
--- a/core/src/components/router/test/guards/href/e2e.ts
+++ /dev/null
@@ -1,125 +0,0 @@
-import { newE2EPage } from '@stencil/core/testing';
-
-test('router: guards - href - allow/allow', async () => {
- const page = await newE2EPage({
- url: '/src/components/router/test/guards?ionic:_testing=true',
- });
-
- // Test 1: beforeEnter: allow, beforeLeave: allow
- await setBeforeEnterHook(page, 'allow');
-
- const href = await page.$('#href');
- await href.click();
-
- await page.waitForChanges();
-
- await checkUrl(page, '#/child');
-
- const backButton = await page.$('ion-back-button');
- await backButton.click();
-
- await page.waitForChanges();
-
- await checkUrl(page, '#/home');
-});
-
-test('router: guards - href - block/allow', async () => {
- const page = await newE2EPage({
- url: '/src/components/router/test/guards?ionic:_testing=true',
- });
-
- // Test 2: beforeEnter: block, beforeLeave: allow
- await setBeforeEnterHook(page, 'block');
-
- const href = await page.$('#href');
- await href.click();
-
- await page.waitForChanges();
-
- await checkUrl(page, '#/home');
-});
-
-test('router: guards - href - redirect/allow', async () => {
- const page = await newE2EPage({
- url: '/src/components/router/test/guards?ionic:_testing=true',
- });
-
- // Test 3: beforeEnter: redirect, beforeLeave: allow
- await setBeforeEnterHook(page, 'redirect');
-
- const href = await page.$('#href');
- await href.click();
-
- await page.waitForChanges();
-
- await checkUrl(page, '#/test');
-
- const backButton = await page.$('ion-back-button');
- await backButton.click();
-
- await page.waitForChanges();
-
- await checkUrl(page, '#/home');
-});
-
-test('router: guards - href - allow/block', async () => {
- const page = await newE2EPage({
- url: '/src/components/router/test/guards?ionic:_testing=true',
- });
-
- // Test 4: beforeEnter: allow, beforeLeave: block
- await setBeforeLeaveHook(page, 'block');
-
- const href = await page.$('#href');
- await href.click();
-
- await page.waitForChanges();
-
- await checkUrl(page, '#/child');
-
- const backButton = await page.$('ion-back-button');
- await backButton.click();
-
- await page.waitForChanges();
-
- await checkUrl(page, '#/child');
-});
-
-// TODO this is an actual bug in the code.
-test('router: guards - href - allow/redirect', async () => {
- const page = await newE2EPage({
- url: '/src/components/router/test/guards?ionic:_testing=true',
- });
-
- // Test 5: beforeEnter: allow, beforeLeave: redirect
- await setBeforeLeaveHook(page, 'redirect');
-
- const href = await page.$('#href');
- await href.click();
-
- await page.waitForChanges();
-
- await checkUrl(page, '#/child');
-
- const backButton = await page.$('ion-back-button');
- await backButton.click();
-
- await page.waitForChanges();
-
- await checkUrl(page, '#/test');
-});
-
-const checkUrl = async (page, url: string) => {
- const getUrl = await page.url();
- expect(getUrl).toContain(url);
-};
-
-const setBeforeEnterHook = async (page, type: string) => {
- const button = await page.$(`ion-radio-group#beforeEnter ion-radio[value=${type}]`);
- await button.click();
-};
-
-const setBeforeLeaveHook = async (page, type: string) => {
- const button = await page.$(`ion-radio-group#beforeLeave ion-radio[value=${type}]`);
- await button.click();
-};
diff --git a/core/src/components/router/test/guards/href/router.e2e.ts b/core/src/components/router/test/guards/href/router.e2e.ts
new file mode 100644
index 0000000000..f87b918f36
--- /dev/null
+++ b/core/src/components/router/test/guards/href/router.e2e.ts
@@ -0,0 +1,90 @@
+import { expect } from '@playwright/test';
+import { test } from '@utils/test/playwright';
+
+import { setBeforeEnterHook, setBeforeLeaveHook } from '../test.utils';
+
+test.describe('router: guards: href', () => {
+ test.beforeEach(async ({ page, skip }) => {
+ skip.mode('md');
+ skip.rtl();
+
+ await page.goto(`/src/components/router/test/guards`);
+ });
+
+ test('allow/allow', async ({ page }) => {
+ // beforeEnter: allow, beforeLeave: allow
+ await setBeforeEnterHook(page, 'allow');
+
+ await page.click('#href');
+ await page.waitForChanges();
+
+ expect(page.url()).toContain('#/child');
+
+ await page.click('ion-back-button');
+ await page.waitForChanges();
+
+ expect(page.url()).toContain('#/home');
+ });
+
+ test('block/allow', async ({ page }) => {
+ // beforeEnter: block, beforeLeave: allow
+ await setBeforeEnterHook(page, 'block');
+
+ await page.click('#href');
+
+ await page.waitForChanges();
+
+ expect(page.url()).toContain('#/home');
+ });
+
+ test('redirect/allow', async ({ page }) => {
+ // beforeEnter: redirect, beforeLeave: allow
+ await setBeforeEnterHook(page, 'redirect');
+
+ await page.click('#href');
+
+ await page.waitForChanges();
+
+ expect(page.url()).toContain('#/test');
+
+ await page.click('ion-back-button');
+
+ await page.waitForChanges();
+
+ expect(page.url()).toContain('#/home');
+ });
+
+ test('allow/bock', async ({ page }) => {
+ // beforeEnter: allow, beforeLeave: block
+ await setBeforeLeaveHook(page, 'block');
+
+ await page.click('#href');
+
+ await page.waitForChanges();
+
+ expect(page.url()).toContain('#/child');
+
+ await page.click('ion-back-button');
+
+ await page.waitForChanges();
+
+ expect(page.url()).toContain('#/child');
+ });
+
+ test('allow/redirect', async ({ page }) => {
+ // beforeEnter: allow, beforeLeave: redirect
+ await setBeforeLeaveHook(page, 'redirect');
+
+ await page.click('#href');
+
+ await page.waitForChanges();
+
+ expect(page.url()).toContain('#/child');
+
+ await page.click('ion-back-button');
+
+ await page.waitForChanges();
+
+ expect(page.url()).toContain('#/test');
+ });
+});
diff --git a/core/src/components/router/test/guards/link/e2e.ts b/core/src/components/router/test/guards/link/e2e.ts
deleted file mode 100644
index c7cf4fd0ee..0000000000
--- a/core/src/components/router/test/guards/link/e2e.ts
+++ /dev/null
@@ -1,124 +0,0 @@
-import { newE2EPage } from '@stencil/core/testing';
-
-test('router: guards - router-link - allow/allow', async () => {
- const page = await newE2EPage({
- url: '/src/components/router/test/guards?ionic:_testing=true',
- });
-
- // Test 1: beforeEnter: allow, beforeLeave: allow
- await setBeforeEnterHook(page, 'allow');
-
- const routerLink = await page.$('#router-link');
- await routerLink.click();
-
- await page.waitForChanges();
-
- await checkUrl(page, '#/child/1');
-
- const backButton = await page.$('ion-back-button');
- await backButton.click();
-
- await page.waitForChanges();
-
- await checkUrl(page, '#/home');
-});
-
-test('router: guards - router-link - block/allow', async () => {
- const page = await newE2EPage({
- url: '/src/components/router/test/guards?ionic:_testing=true',
- });
-
- // Test 2: beforeEnter: block, beforeLeave: allow
- await setBeforeEnterHook(page, 'block');
-
- const routerLink = await page.$('#router-link');
- await routerLink.click();
-
- await page.waitForChanges();
-
- await checkUrl(page, '#/home');
-});
-
-test('router: guards - router-link - redirect/allow', async () => {
- const page = await newE2EPage({
- url: '/src/components/router/test/guards?ionic:_testing=true',
- });
-
- // Test 3: beforeEnter: redirect, beforeLeave: allow
- await setBeforeEnterHook(page, 'redirect');
-
- const routerLink = await page.$('#router-link');
- await routerLink.click();
-
- await page.waitForChanges();
-
- await checkUrl(page, '#/test');
-
- const backButton = await page.$('ion-back-button');
- await backButton.click();
-
- await page.waitForChanges();
-
- await checkUrl(page, '#/home');
-});
-
-test('router: guards - router-link - allow/block', async () => {
- const page = await newE2EPage({
- url: '/src/components/router/test/guards?ionic:_testing=true',
- });
-
- // Test 4: beforeEnter: allow, beforeLeave: block
- await setBeforeLeaveHook(page, 'block');
-
- const routerLink = await page.$('#router-link');
- await routerLink.click();
-
- await page.waitForChanges();
-
- await checkUrl(page, '#/child/1');
-
- const backButton = await page.$('ion-back-button');
- await backButton.click();
-
- await page.waitForChanges();
-
- await checkUrl(page, '#/child/1');
-});
-
-test('router: guards - router-link - allow/redirect', async () => {
- const page = await newE2EPage({
- url: '/src/components/router/test/guards?ionic:_testing=true',
- });
-
- // Test 5: beforeEnter: allow, beforeLeave: redirect
- await setBeforeLeaveHook(page, 'redirect');
-
- const routerLink = await page.$('#router-link');
- await routerLink.click();
-
- await page.waitForChanges();
-
- await checkUrl(page, '#/child/1');
-
- const backButton = await page.$('ion-back-button');
- await backButton.click();
-
- await page.waitForChanges();
-
- await checkUrl(page, '#/test');
-});
-
-const checkUrl = async (page, url: string) => {
- const getUrl = await page.url();
- expect(getUrl).toContain(url);
-};
-
-const setBeforeEnterHook = async (page, type: string) => {
- const button = await page.$(`ion-radio-group#beforeEnter ion-radio[value=${type}]`);
- await button.click();
-};
-
-const setBeforeLeaveHook = async (page, type: string) => {
- const button = await page.$(`ion-radio-group#beforeLeave ion-radio[value=${type}]`);
- await button.click();
-};
diff --git a/core/src/components/router/test/guards/link/router.e2e.ts b/core/src/components/router/test/guards/link/router.e2e.ts
new file mode 100644
index 0000000000..6fd1f01e4a
--- /dev/null
+++ b/core/src/components/router/test/guards/link/router.e2e.ts
@@ -0,0 +1,92 @@
+import { expect } from '@playwright/test';
+import { test } from '@utils/test/playwright';
+
+import { setBeforeEnterHook, setBeforeLeaveHook } from '../test.utils';
+
+test.describe('router: guards: router-link', () => {
+ test.beforeEach(async ({ page, skip }) => {
+ skip.mode('md');
+ skip.rtl();
+
+ await page.goto(`/src/components/router/test/guards`);
+ });
+
+ test('allow/allow', async ({ page }) => {
+ // beforeEnter: allow, beforeLeave: allow
+ await setBeforeEnterHook(page, 'allow');
+
+ await page.click('#router-link');
+
+ await page.waitForChanges();
+
+ expect(page.url()).toContain('#/child/1');
+
+ await page.click('ion-back-button');
+
+ await page.waitForChanges();
+
+ expect(page.url()).toContain('#/home');
+ });
+
+ test('block/allow', async ({ page }) => {
+ // beforeEnter: block, beforeLeave: allow
+ await setBeforeEnterHook(page, 'block');
+
+ await page.click('#router-link');
+
+ await page.waitForChanges();
+
+ expect(page.url()).toContain('#/home');
+ });
+
+ test('redirect/allow', async ({ page }) => {
+ // beforeEnter: redirect, beforeLeave: allow
+ await setBeforeEnterHook(page, 'redirect');
+
+ await page.click('#router-link');
+
+ await page.waitForChanges();
+
+ expect(page.url()).toContain('#/test');
+
+ await page.click('ion-back-button');
+
+ await page.waitForChanges();
+
+ expect(page.url()).toContain('#/home');
+ });
+
+ test('allow/block', async ({ page }) => {
+ // beforeEnter: allow, beforeLeave: block
+ await setBeforeLeaveHook(page, 'block');
+
+ await page.click('#router-link');
+
+ await page.waitForChanges();
+
+ expect(page.url()).toContain('#/child/1');
+
+ await page.click('ion-back-button');
+
+ await page.waitForChanges();
+
+ expect(page.url()).toContain('#/child/1');
+ });
+
+ test('allow/redirect', async ({ page }) => {
+ // beforeEnter: allow, beforeLeave: redirect
+ await setBeforeLeaveHook(page, 'redirect');
+
+ await page.click('#router-link');
+
+ await page.waitForChanges();
+
+ expect(page.url()).toContain('#/child/1');
+
+ await page.click('ion-back-button');
+
+ await page.waitForChanges();
+
+ expect(page.url()).toContain('#/test');
+ });
+});
diff --git a/core/src/components/router/test/guards/push/e2e.ts b/core/src/components/router/test/guards/push/e2e.ts
deleted file mode 100644
index e73b800f7b..0000000000
--- a/core/src/components/router/test/guards/push/e2e.ts
+++ /dev/null
@@ -1,124 +0,0 @@
-import { newE2EPage } from '@stencil/core/testing';
-
-test('router: guards - router.push - allow/allow', async () => {
- const page = await newE2EPage({
- url: '/src/components/router/test/guards?ionic:_testing=true',
- });
-
- // Test 1: beforeEnter: allow, beforeLeave: allow
- await setBeforeEnterHook(page, 'allow');
-
- const routerPush = await page.$('#router-push');
- await routerPush.click();
-
- await page.waitForChanges();
-
- await checkUrl(page, '#/child');
-
- const backButton = await page.$('ion-back-button');
- await backButton.click();
-
- await page.waitForChanges();
-
- await checkUrl(page, '#/home');
-});
-
-test('router: guards - router.push - block/allow', async () => {
- const page = await newE2EPage({
- url: '/src/components/router/test/guards?ionic:_testing=true',
- });
-
- // Test 2: beforeEnter: block, beforeLeave: allow
- await setBeforeEnterHook(page, 'block');
-
- const routerPush = await page.$('#router-push');
- await routerPush.click();
-
- await page.waitForChanges();
-
- await checkUrl(page, '#/home');
-});
-
-test('router: guards - router.push - redirect/allow', async () => {
- const page = await newE2EPage({
- url: '/src/components/router/test/guards?ionic:_testing=true',
- });
-
- // Test 3: beforeEnter: redirect, beforeLeave: allow
- await setBeforeEnterHook(page, 'redirect');
-
- const routerPush = await page.$('#router-push');
- await routerPush.click();
-
- await page.waitForChanges();
-
- await checkUrl(page, '#/test');
-
- const backButton = await page.$('ion-back-button');
- await backButton.click();
-
- await page.waitForChanges();
-
- await checkUrl(page, '#/home');
-});
-
-test('router: guards - router.push - allow/block', async () => {
- const page = await newE2EPage({
- url: '/src/components/router/test/guards?ionic:_testing=true',
- });
-
- // Test 4: beforeEnter: allow, beforeLeave: block
- await setBeforeLeaveHook(page, 'block');
-
- const routerPush = await page.$('#router-push');
- await routerPush.click();
-
- await page.waitForChanges();
-
- await checkUrl(page, '#/child');
-
- const backButton = await page.$('ion-back-button');
- await backButton.click();
-
- await page.waitForChanges();
-
- await checkUrl(page, '#/child');
-});
-
-test('router: guards - router.push - allow/redirect', async () => {
- const page = await newE2EPage({
- url: '/src/components/router/test/guards?ionic:_testing=true',
- });
-
- // Test 5: beforeEnter: allow, beforeLeave: redirect
- await setBeforeLeaveHook(page, 'redirect');
-
- const routerPush = await page.$('#router-push');
- await routerPush.click();
-
- await page.waitForChanges();
-
- await checkUrl(page, '#/child');
-
- const backButton = await page.$('ion-back-button');
- await backButton.click();
-
- await page.waitForChanges();
-
- await checkUrl(page, '#/test');
-});
-
-const checkUrl = async (page, url: string) => {
- const getUrl = await page.url();
- expect(getUrl).toContain(url);
-};
-
-const setBeforeEnterHook = async (page, type: string) => {
- const button = await page.$(`ion-radio-group#beforeEnter ion-radio[value=${type}]`);
- await button.click();
-};
-
-const setBeforeLeaveHook = async (page, type: string) => {
- const button = await page.$(`ion-radio-group#beforeLeave ion-radio[value=${type}]`);
- await button.click();
-};
diff --git a/core/src/components/router/test/guards/push/router.e2e.ts b/core/src/components/router/test/guards/push/router.e2e.ts
new file mode 100644
index 0000000000..6aec67ef96
--- /dev/null
+++ b/core/src/components/router/test/guards/push/router.e2e.ts
@@ -0,0 +1,92 @@
+import { expect } from '@playwright/test';
+import { test } from '@utils/test/playwright';
+
+import { setBeforeEnterHook, setBeforeLeaveHook } from '../test.utils';
+
+test.describe('router: guards: router.push', () => {
+ test.beforeEach(async ({ page, skip }) => {
+ skip.mode('md');
+ skip.rtl();
+
+ await page.goto(`/src/components/router/test/guards`);
+ });
+
+ test('allow/allow', async ({ page }) => {
+ // beforeEnter: allow, beforeLeave: allow
+ await setBeforeEnterHook(page, 'allow');
+
+ await page.click('#router-push');
+
+ await page.waitForChanges();
+
+ expect(page.url()).toContain('#/child');
+
+ await page.click('ion-back-button');
+
+ await page.waitForChanges();
+
+ expect(page.url()).toContain('#/home');
+ });
+
+ test('block/allow', async ({ page }) => {
+ // beforeEnter: block, beforeLeave: allow
+ await setBeforeEnterHook(page, 'block');
+
+ await page.click('#router-push');
+
+ await page.waitForChanges();
+
+ expect(page.url()).toContain('#/home');
+ });
+
+ test('redirect/allow', async ({ page }) => {
+ // beforeEnter: redirect, beforeLeave: allow
+ await setBeforeEnterHook(page, 'redirect');
+
+ await page.click('#router-push');
+
+ await page.waitForChanges();
+
+ expect(page.url()).toContain('#/test');
+
+ await page.click('ion-back-button');
+
+ await page.waitForChanges();
+
+ expect(page.url()).toContain('#/home');
+ });
+
+ test('allow/block', async ({ page }) => {
+ // beforeEnter: allow, beforeLeave: block
+ await setBeforeLeaveHook(page, 'block');
+
+ await page.click('#router-push');
+
+ await page.waitForChanges();
+
+ expect(page.url()).toContain('#/child');
+
+ await page.click('ion-back-button');
+
+ await page.waitForChanges();
+
+ expect(page.url()).toContain('#/child');
+ });
+
+ test('allow/redirect', async ({ page }) => {
+ // beforeEnter: allow, beforeLeave: redirect
+ await setBeforeLeaveHook(page, 'redirect');
+
+ await page.click('#router-push');
+
+ await page.waitForChanges();
+
+ expect(page.url()).toContain('#/child');
+
+ await page.click('ion-back-button');
+
+ await page.waitForChanges();
+
+ expect(page.url()).toContain('#/test');
+ });
+});
diff --git a/core/src/components/router/test/guards/router.e2e.ts b/core/src/components/router/test/guards/router.e2e.ts
new file mode 100644
index 0000000000..000209713c
--- /dev/null
+++ b/core/src/components/router/test/guards/router.e2e.ts
@@ -0,0 +1,15 @@
+import { expect } from '@playwright/test';
+import { test } from '@utils/test/playwright';
+
+test.describe('router: guards', () => {
+ test.beforeEach(({ skip }) => {
+ skip.mode('md');
+ skip.rtl();
+ });
+
+ test('guards should be run on initial load', async ({ page }) => {
+ await page.goto(`/src/components/router/test/guards#/guard-initial-page`);
+
+ expect(page.url()).toContain('#/child/1');
+ });
+});
diff --git a/core/src/components/router/test/guards/test.utils.ts b/core/src/components/router/test/guards/test.utils.ts
new file mode 100644
index 0000000000..bd67a6548e
--- /dev/null
+++ b/core/src/components/router/test/guards/test.utils.ts
@@ -0,0 +1,17 @@
+import type { Page } from '@playwright/test';
+
+/**
+ * Selects a radio button from the radio group for configuring the
+ * beforeEnter hook of the router.
+ */
+export const setBeforeEnterHook = async (page: Page, type: string) => {
+ await page.click(`ion-radio-group#beforeEnter ion-radio[value=${type}]`);
+};
+
+/**
+ * Selects a radio button from the radio group for configuring the
+ * beforeLeave hook of the router.
+ */
+export const setBeforeLeaveHook = async (page: Page, type: string) => {
+ await page.click(`ion-radio-group#beforeLeave ion-radio[value=${type}]`);
+};
diff --git a/core/src/components/router/test/tabs/e2e.ts b/core/src/components/router/test/tabs/e2e.ts
deleted file mode 100644
index d14367a823..0000000000
--- a/core/src/components/router/test/tabs/e2e.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-import { newE2EPage } from '@stencil/core/testing';
-
-test('router: tabs', async () => {
- const page = await newE2EPage({
- url: '/src/components/router/test/tabs?ionic:_testing=true',
- });
-
- const compare = await page.compareScreenshot();
- expect(compare).toMatchScreenshot();
-});
diff --git a/core/src/components/router/test/tabs/index.html b/core/src/components/router/test/tabs/index.html
deleted file mode 100644
index 15b30d931b..0000000000
--- a/core/src/components/router/test/tabs/index.html
+++ /dev/null
@@ -1,146 +0,0 @@
-
-
-
-
- Nav
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-