test(e2e): add infrastructure for migration to playwright (#25033)
@ -28,3 +28,8 @@ runs:
|
|||||||
name: ionic-core
|
name: ionic-core
|
||||||
output: core/CoreBuild.zip
|
output: core/CoreBuild.zip
|
||||||
paths: core/dist core/components core/css core/hydrate core/loader
|
paths: core/dist core/components core/css core/hydrate core/loader
|
||||||
|
- uses: ./.github/workflows/actions/upload-archive
|
||||||
|
with:
|
||||||
|
name: ionic-core-src
|
||||||
|
output: core/CoreSrc.zip
|
||||||
|
paths: core/src
|
||||||
|
@ -1,33 +0,0 @@
|
|||||||
name: 'Test Core Screenshot Main'
|
|
||||||
description: 'Test Core Screenshot Main'
|
|
||||||
inputs:
|
|
||||||
access-key-id:
|
|
||||||
description: 'AWS_ACCESS_KEY_ID'
|
|
||||||
secret-access-key:
|
|
||||||
description: 'AWS_SECRET_ACCESS_KEY'
|
|
||||||
runs:
|
|
||||||
using: 'composite'
|
|
||||||
steps:
|
|
||||||
- uses: actions/setup-node@v1
|
|
||||||
with:
|
|
||||||
node-version: 15.x
|
|
||||||
|
|
||||||
- name: Cache Core Node Modules
|
|
||||||
uses: actions/cache@v2
|
|
||||||
env:
|
|
||||||
cache-name: core-node-modules
|
|
||||||
with:
|
|
||||||
path: ./core/node_modules
|
|
||||||
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('./core/package-lock.json') }}-v2
|
|
||||||
- uses: ./.github/workflows/actions/download-archive
|
|
||||||
with:
|
|
||||||
name: ionic-core
|
|
||||||
path: ./core
|
|
||||||
filename: CoreBuild.zip
|
|
||||||
- name: Test
|
|
||||||
run: npx stencil test --e2e --screenshot --screenshot-connector=scripts/screenshot/ci.js --ci --update-screenshot --no-build || true
|
|
||||||
shell: bash
|
|
||||||
env:
|
|
||||||
AWS_ACCESS_KEY_ID: ${{ inputs.access-key-id }}
|
|
||||||
AWS_SECRET_ACCESS_KEY: ${{ inputs.secret-access-key }}
|
|
||||||
working-directory: ./core
|
|
@ -1,10 +1,12 @@
|
|||||||
name: 'Test Core Screenshot'
|
name: 'Test Core Screenshot'
|
||||||
description: 'Test Core Screenshot'
|
description: 'Test Core Screenshot'
|
||||||
inputs:
|
inputs:
|
||||||
access-key-id:
|
shard:
|
||||||
description: 'AWS_ACCESS_KEY_ID'
|
description: 'Playwright Test Shard (ex: 2)'
|
||||||
secret-access-key:
|
totalShards:
|
||||||
description: 'AWS_SECRET_ACCESS_KEY'
|
description: 'Playwright total number of test shards (ex: 4)'
|
||||||
|
update:
|
||||||
|
description: 'Whether or not to update the reference snapshots'
|
||||||
runs:
|
runs:
|
||||||
using: 'composite'
|
using: 'composite'
|
||||||
steps:
|
steps:
|
||||||
@ -24,10 +26,35 @@ runs:
|
|||||||
name: ionic-core
|
name: ionic-core
|
||||||
path: ./core
|
path: ./core
|
||||||
filename: CoreBuild.zip
|
filename: CoreBuild.zip
|
||||||
- name: Test
|
- uses: ./.github/workflows/actions/download-archive
|
||||||
run: npx stencil test --e2e --screenshot --screenshot-connector=scripts/screenshot/ci.js --ci --no-build || true
|
with:
|
||||||
|
name: ionic-core-src
|
||||||
|
path: ./core
|
||||||
|
filename: CoreSrc.zip
|
||||||
|
- name: Install Playwright Dependencies
|
||||||
|
run: npx playwright install && npx playwright install-deps
|
||||||
shell: bash
|
shell: bash
|
||||||
env:
|
|
||||||
AWS_ACCESS_KEY_ID: ${{ inputs.access-key-id }}
|
|
||||||
AWS_SECRET_ACCESS_KEY: ${{ inputs.secret-access-key }}
|
|
||||||
working-directory: ./core
|
working-directory: ./core
|
||||||
|
- name: Test
|
||||||
|
if: inputs.update != 'true'
|
||||||
|
run: npx playwright test --shard=${{ inputs.shard }}/${{ inputs.totalShards }}
|
||||||
|
shell: bash
|
||||||
|
working-directory: ./core
|
||||||
|
- name: Test and Update
|
||||||
|
if: inputs.update == 'true'
|
||||||
|
run: npx playwright test --shard=${{ inputs.shard }}/${{ inputs.totalShards }} --update-snapshots
|
||||||
|
shell: bash
|
||||||
|
working-directory: ./core
|
||||||
|
- name: Archive Test Results
|
||||||
|
# The always() ensures that this step
|
||||||
|
# runs even if the previous step fails.
|
||||||
|
# We want the test results to be archived
|
||||||
|
# even if the test fails in the previous
|
||||||
|
# step, otherwise there would be no way
|
||||||
|
# to debug these tests.
|
||||||
|
if: always()
|
||||||
|
uses: ./.github/workflows/actions/upload-archive
|
||||||
|
with:
|
||||||
|
name: test-results-${{ inputs.shard }}-${{ inputs.totalShards }}
|
||||||
|
output: core/TestResults-${{ inputs.shard }}-${{ inputs.totalShards }}.zip
|
||||||
|
paths: core/playwright-report core/src
|
||||||
|
35
.github/workflows/actions/update-reference-screenshots/action.yml
vendored
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
name: 'Update Reference Screenshots'
|
||||||
|
description: 'Update Reference Screenshots'
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
runs:
|
||||||
|
using: 'composite'
|
||||||
|
steps:
|
||||||
|
- uses: actions/setup-node@v1
|
||||||
|
with:
|
||||||
|
node-version: 15.x
|
||||||
|
- uses: actions/download-artifact@v2
|
||||||
|
with:
|
||||||
|
path: ./artifacts
|
||||||
|
- name: Extract Archives
|
||||||
|
# This finds all .zip files in the ./artifacts
|
||||||
|
# directory, including nested directories.
|
||||||
|
# It then unzips every .zip to the root directory
|
||||||
|
run: |
|
||||||
|
find . -type f -name '*.zip' -exec unzip -q -o -d ../ -- '{}' -x '*.zip' \;
|
||||||
|
shell: bash
|
||||||
|
working-directory: ./artifacts
|
||||||
|
- name: Push Screenshots
|
||||||
|
# Configure user as Ionitron
|
||||||
|
# and push only the changed .png snapshots
|
||||||
|
# to the remote branch.
|
||||||
|
run: |
|
||||||
|
git config user.name ionitron
|
||||||
|
git config user.email hi@ionicframework.com
|
||||||
|
git add src/\*.png
|
||||||
|
git commit -m "chore(): add updated snapshots"
|
||||||
|
git push
|
||||||
|
shell: bash
|
||||||
|
working-directory: ./core
|
30
.github/workflows/build.yml
vendored
@ -40,26 +40,28 @@ jobs:
|
|||||||
- uses: ./.github/workflows/actions/test-core-e2e
|
- uses: ./.github/workflows/actions/test-core-e2e
|
||||||
|
|
||||||
test-core-screenshot:
|
test-core-screenshot:
|
||||||
|
strategy:
|
||||||
|
# This ensures that all screenshot shard
|
||||||
|
# failures are reported so the dev can
|
||||||
|
# review everything at once.
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
# Divide the tests into n buckets
|
||||||
|
# and run those buckets in parallel.
|
||||||
|
# To increase the number of shards,
|
||||||
|
# add new items to the shard array
|
||||||
|
# and change the value of totalShards
|
||||||
|
# to be the length of the shard array.
|
||||||
|
shard: [1, 2, 3, 4, 5]
|
||||||
|
totalShards: [5]
|
||||||
needs: [build-core]
|
needs: [build-core]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: github.ref != 'refs/heads/main' && !github.event.pull_request.head.repo.fork
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- uses: ./.github/workflows/actions/test-core-screenshot
|
- uses: ./.github/workflows/actions/test-core-screenshot
|
||||||
with:
|
with:
|
||||||
access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
shard: ${{ matrix.shard }}
|
||||||
secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
totalShards: ${{ matrix.totalShards }}
|
||||||
|
|
||||||
test-core-screenshot-main:
|
|
||||||
needs: [build-core]
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: github.ref == 'refs/heads/main'
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- uses: ./.github/workflows/actions/test-core-screenshot-main
|
|
||||||
with:
|
|
||||||
access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
|
||||||
secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
|
||||||
|
|
||||||
build-vue:
|
build-vue:
|
||||||
needs: [build-core]
|
needs: [build-core]
|
||||||
|
51
.github/workflows/update-screenshots.yml
vendored
@ -1,11 +1,52 @@
|
|||||||
name: 'Update Screenshot References'
|
name: 'Update Reference Screenshots'
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
stub:
|
build-core:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Stub
|
- uses: actions/checkout@v2
|
||||||
run: echo 'This is a stub'
|
- uses: ./.github/workflows/actions/build-core
|
||||||
shell: bash
|
|
||||||
|
test-core-screenshot:
|
||||||
|
strategy:
|
||||||
|
# This ensures that all screenshot shard
|
||||||
|
# failures are reported so the dev can
|
||||||
|
# review everything at once.
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
# Divide the tests into n buckets
|
||||||
|
# and run those buckets in parallel.
|
||||||
|
# To increase the number of shards,
|
||||||
|
# add new items to the shard array
|
||||||
|
# and change the value of totalShards
|
||||||
|
# to be the length of the shard array.
|
||||||
|
shard: [1, 2, 3, 4, 5]
|
||||||
|
totalShards: [5]
|
||||||
|
needs: [build-core]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- uses: ./.github/workflows/actions/test-core-screenshot
|
||||||
|
with:
|
||||||
|
shard: ${{ matrix.shard }}
|
||||||
|
totalShards: ${{ matrix.totalShards }}
|
||||||
|
update: true
|
||||||
|
|
||||||
|
update-reference-screenshots:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: [test-core-screenshot]
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
# Normally, we could just push with the
|
||||||
|
# default GITHUB_TOKEN, but that will
|
||||||
|
# not cause the build workflow
|
||||||
|
# to re-run. We use Ionitron's
|
||||||
|
# Personal Access Token instead
|
||||||
|
# to allow for this build workflow
|
||||||
|
# to run when the screenshots are pushed.
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.IONITRON_TOKEN }}
|
||||||
|
- uses: ./.github/workflows/actions/update-reference-screenshots
|
||||||
|
4
.gitignore
vendored
@ -67,4 +67,8 @@ core/www/
|
|||||||
.stencil/
|
.stencil/
|
||||||
angular/build/
|
angular/build/
|
||||||
|
|
||||||
|
# playwright
|
||||||
|
core/test-results/
|
||||||
|
core/playwright-report/
|
||||||
|
|
||||||
.npmrc
|
.npmrc
|
||||||
|
3254
core/package-lock.json
generated
@ -38,6 +38,7 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@axe-core/puppeteer": "^4.3.2",
|
"@axe-core/puppeteer": "^4.3.2",
|
||||||
"@jest/core": "^26.6.3",
|
"@jest/core": "^26.6.3",
|
||||||
|
"@playwright/test": "^1.20.0",
|
||||||
"@rollup/plugin-node-resolve": "^8.4.0",
|
"@rollup/plugin-node-resolve": "^8.4.0",
|
||||||
"@rollup/plugin-virtual": "^2.0.3",
|
"@rollup/plugin-virtual": "^2.0.3",
|
||||||
"@stencil/angular-output-target": "^0.4.0",
|
"@stencil/angular-output-target": "^0.4.0",
|
||||||
|
109
core/playwright.config.ts
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
import type { PlaywrightTestConfig } from '@playwright/test';
|
||||||
|
import { devices } from '@playwright/test';
|
||||||
|
|
||||||
|
const projects = [
|
||||||
|
{
|
||||||
|
name: 'chromium',
|
||||||
|
|
||||||
|
use: {
|
||||||
|
...devices['Desktop Chrome'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'firefox',
|
||||||
|
use: {
|
||||||
|
...devices['Desktop Firefox'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'webkit',
|
||||||
|
use: {
|
||||||
|
...devices['Desktop Safari'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Mobile Chrome',
|
||||||
|
use: {
|
||||||
|
...devices['Pixel 5']
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Mobile Safari',
|
||||||
|
use: {
|
||||||
|
...devices['iPhone 12']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const modes = ['ios', 'md'];
|
||||||
|
|
||||||
|
const generateProjects = () => {
|
||||||
|
const projectsWithMetadata = [];
|
||||||
|
|
||||||
|
modes.forEach(mode => {
|
||||||
|
projects.forEach(project => {
|
||||||
|
projectsWithMetadata.push({
|
||||||
|
...project,
|
||||||
|
metadata: {
|
||||||
|
mode,
|
||||||
|
rtl: false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
projectsWithMetadata.push({
|
||||||
|
...project,
|
||||||
|
metadata: {
|
||||||
|
mode,
|
||||||
|
rtl: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return projectsWithMetadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See https://playwright.dev/docs/test-configuration.
|
||||||
|
*/
|
||||||
|
const config: PlaywrightTestConfig = {
|
||||||
|
testMatch: '*.e2e.ts',
|
||||||
|
expect: {
|
||||||
|
/**
|
||||||
|
* Maximum time expect() should wait for the condition to be met.
|
||||||
|
* For example in `await expect(locator).toHaveText();`
|
||||||
|
*/
|
||||||
|
timeout: 5000
|
||||||
|
},
|
||||||
|
/* Fail the build on CI if you accidentally left test.only in the source code. */
|
||||||
|
forbidOnly: !!process.env.CI,
|
||||||
|
retries: 0,
|
||||||
|
/* Opt out of parallel tests on CI. */
|
||||||
|
workers: process.env.CI ? 1 : undefined,
|
||||||
|
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
||||||
|
reporter: 'html',
|
||||||
|
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
||||||
|
use: {
|
||||||
|
/* Maximum time each action such as `click()` can take. Defaults to 0 (no limit). */
|
||||||
|
actionTimeout: 0,
|
||||||
|
/* Base URL to use in actions like `await page.goto('/')`. */
|
||||||
|
// baseURL: 'http://localhost:3000',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All failed tests should create
|
||||||
|
* a trace file for easier debugging.
|
||||||
|
*
|
||||||
|
* See https://playwright.dev/docs/trace-viewer
|
||||||
|
*/
|
||||||
|
trace: 'retain-on-failure',
|
||||||
|
baseURL: 'http://localhost:3333',
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Configure projects for major browsers */
|
||||||
|
projects: generateProjects(),
|
||||||
|
webServer: {
|
||||||
|
command: 'python3 -m http.server 3333',
|
||||||
|
port: '3333'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default config;
|
@ -17,4 +17,59 @@
|
|||||||
window.Ionic = window.Ionic || {};
|
window.Ionic = window.Ionic || {};
|
||||||
window.Ionic.config = window.Ionic.config || {};
|
window.Ionic.config = window.Ionic.config || {};
|
||||||
|
|
||||||
})();
|
/**
|
||||||
|
* Waits for all child Stencil components
|
||||||
|
* to be ready before resolving.
|
||||||
|
* This logic is pulled from the Stencil
|
||||||
|
* core codebase for testing with Puppeteer:
|
||||||
|
* https://github.com/ionic-team/stencil/blob/16b8ea4dabb22024872a38bc58ba1dcf1c7cc25b/src/testing/puppeteer/puppeteer-events.ts#L158-L183
|
||||||
|
*/
|
||||||
|
const allReady = () => {
|
||||||
|
const promises = [];
|
||||||
|
const waitForDidLoad = (promises, elm) => {
|
||||||
|
if (elm != null && elm.nodeType === 1) {
|
||||||
|
for (let i = 0; i < elm.children.length; i++) {
|
||||||
|
const childElm = elm.children[i];
|
||||||
|
if (childElm.tagName.includes('-') && typeof childElm.componentOnReady === 'function') {
|
||||||
|
promises.push(childElm.componentOnReady());
|
||||||
|
}
|
||||||
|
waitForDidLoad(promises, childElm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
waitForDidLoad(promises, window.document.documentElement);
|
||||||
|
|
||||||
|
return Promise.all(promises).catch((e) => console.error(e));
|
||||||
|
};
|
||||||
|
|
||||||
|
const waitFrame = () => {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
requestAnimationFrame(resolve);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const stencilReady = () => {
|
||||||
|
return allReady()
|
||||||
|
.then(() => waitFrame())
|
||||||
|
.then(() => allReady())
|
||||||
|
.then(() => {
|
||||||
|
window.stencilAppLoaded = true;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Testing solutions can wait for `window.stencilAppLoaded === true`
|
||||||
|
* to know when to proceed with the test.
|
||||||
|
*/
|
||||||
|
if (window.document.readyState === 'complete') {
|
||||||
|
stencilReady();
|
||||||
|
} else {
|
||||||
|
document.addEventListener('readystatechange', function (e) {
|
||||||
|
if (e.target.readyState == 'complete') {
|
||||||
|
stencilReady();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
})();
|
||||||
|
12
core/src/components/button/test/basic/button.e2e.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { expect, describe } from '@playwright/test';
|
||||||
|
import { test } from '@utils/test/playwright';
|
||||||
|
|
||||||
|
test.describe('button: basic', () => {
|
||||||
|
test('should not have visual regressions', async ({ page }) => {
|
||||||
|
await page.goto(`/src/components/button/test/basic`);
|
||||||
|
|
||||||
|
await page.setIonViewport();
|
||||||
|
|
||||||
|
expect(await page.screenshot({ fullPage: true })).toMatchSnapshot(`button-diff-${page.getSnapshotSettings()}.png`);
|
||||||
|
});
|
||||||
|
});
|
After Width: | Height: | Size: 306 KiB |
After Width: | Height: | Size: 278 KiB |
After Width: | Height: | Size: 77 KiB |
After Width: | Height: | Size: 123 KiB |
After Width: | Height: | Size: 166 KiB |
After Width: | Height: | Size: 304 KiB |
After Width: | Height: | Size: 278 KiB |
After Width: | Height: | Size: 77 KiB |
After Width: | Height: | Size: 123 KiB |
After Width: | Height: | Size: 167 KiB |
After Width: | Height: | Size: 299 KiB |
After Width: | Height: | Size: 277 KiB |
After Width: | Height: | Size: 81 KiB |
After Width: | Height: | Size: 138 KiB |
After Width: | Height: | Size: 174 KiB |
After Width: | Height: | Size: 300 KiB |
After Width: | Height: | Size: 277 KiB |
After Width: | Height: | Size: 81 KiB |
After Width: | Height: | Size: 136 KiB |
After Width: | Height: | Size: 175 KiB |
@ -1,10 +0,0 @@
|
|||||||
import { newE2EPage } from '@stencil/core/testing';
|
|
||||||
|
|
||||||
test('button: basic', async () => {
|
|
||||||
const page = await newE2EPage({
|
|
||||||
url: '/src/components/button/test/basic?ionic:_testing=true'
|
|
||||||
});
|
|
||||||
|
|
||||||
const compare = await page.compareScreenshot();
|
|
||||||
expect(compare).toMatchScreenshot();
|
|
||||||
});
|
|
97
core/src/utils/test/playwright.ts
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
import { test as base } from '@playwright/test';
|
||||||
|
|
||||||
|
export const test = base.extend({
|
||||||
|
page: async ({ page }, use, testInfo) => {
|
||||||
|
const oldGoTo = page.goto.bind(page);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is an extended version of Playwright's
|
||||||
|
* page.goto method. In addition to performing
|
||||||
|
* the normal page.goto work, this code also
|
||||||
|
* automatically waits for the Stencil components
|
||||||
|
* to be hydrated before proceeding with the test.
|
||||||
|
*/
|
||||||
|
page.goto = (url: string) => {
|
||||||
|
const { mode, rtl } = testInfo.project.metadata;
|
||||||
|
|
||||||
|
const splitUrl = url.split('?');
|
||||||
|
const paramsString = splitUrl[1];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This allows developers to force a
|
||||||
|
* certain mode or LTR/RTL config per test.
|
||||||
|
*/
|
||||||
|
const urlToParams = new URLSearchParams(paramsString);
|
||||||
|
const formattedMode = urlToParams.get('ionic:mode') ?? mode;
|
||||||
|
const formattedRtl = urlToParams.get('rtl') ?? rtl;
|
||||||
|
|
||||||
|
const formattedUrl = `${splitUrl[0]}?ionic:_testing=true&ionic:mode=${formattedMode}&rtl=${formattedRtl}`;
|
||||||
|
|
||||||
|
return Promise.all([
|
||||||
|
page.waitForFunction(() => window.stencilAppLoaded === true),
|
||||||
|
oldGoTo(formattedUrl)
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This provides metadata that can be used to
|
||||||
|
* create a unique screenshot URL.
|
||||||
|
* For example, we need to be able to differentiate
|
||||||
|
* between iOS in LTR mode and iOS in RTL mode.
|
||||||
|
*/
|
||||||
|
page.getSnapshotSettings = () => {
|
||||||
|
const url = page.url();
|
||||||
|
const splitUrl = url.split('?');
|
||||||
|
const paramsString = splitUrl[1];
|
||||||
|
|
||||||
|
const { mode, rtl } = testInfo.project.metadata;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Account for custom settings when overriding
|
||||||
|
* the mode/rtl setting. Fall back to the
|
||||||
|
* project metadata if nothing was found. This
|
||||||
|
* will happen if you call page.getSnapshotSettings
|
||||||
|
* before page.goto.
|
||||||
|
*/
|
||||||
|
const urlToParams = new URLSearchParams(paramsString);
|
||||||
|
const formattedMode = urlToParams.get('ionic:mode') ?? mode;
|
||||||
|
const formattedRtl = urlToParams.get('rtl') ?? rtl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If encoded in the search params, the rtl value
|
||||||
|
* can be `'true'` instead of `true`.
|
||||||
|
*/
|
||||||
|
const rtlString = formattedRtl === true || formattedRtl === 'true' ? 'rtl' : 'ltr';
|
||||||
|
return `${formattedMode}-${rtlString}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Taking fullpage screenshots in Playwright
|
||||||
|
* does not work with ion-content by default.
|
||||||
|
* The reason is that full page screenshots do not
|
||||||
|
* expand any scrollable container on the page. Instead,
|
||||||
|
* they render the full scrollable content of the document itself.
|
||||||
|
* To work around this, we increase the size of the document
|
||||||
|
* so the full scrollable content inside of ion-content
|
||||||
|
* can be captured in a screenshot.
|
||||||
|
*/
|
||||||
|
page.setIonViewport = async () => {
|
||||||
|
const currentViewport = await page.viewportSize();
|
||||||
|
|
||||||
|
const pixelAmountRenderedOffscreen = await page.evaluate(() => {
|
||||||
|
const content = document.querySelector('ion-content');
|
||||||
|
const innerScroll = content.shadowRoot.querySelector('.inner-scroll');
|
||||||
|
|
||||||
|
return innerScroll.scrollHeight - content.clientHeight;
|
||||||
|
});
|
||||||
|
|
||||||
|
await page.setViewportSize({
|
||||||
|
width: currentViewport.width,
|
||||||
|
height: currentViewport.height + pixelAmountRenderedOffscreen
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
await use(page);
|
||||||
|
},
|
||||||
|
});
|
@ -258,6 +258,7 @@ export const config: Config = {
|
|||||||
scriptDataOpts: true
|
scriptDataOpts: true
|
||||||
},
|
},
|
||||||
testing: {
|
testing: {
|
||||||
|
testRegex: '(/__tests__/.*|(\\.|/)(test|spec)|[//](e2e))\\.[jt]sx?$',
|
||||||
allowableMismatchedPixels: 200,
|
allowableMismatchedPixels: 200,
|
||||||
pixelmatchThreshold: 0.05,
|
pixelmatchThreshold: 0.05,
|
||||||
waitBeforeScreenshot: 20,
|
waitBeforeScreenshot: 20,
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
"target": "es2017",
|
"target": "es2017",
|
||||||
"baseUrl": ".",
|
"baseUrl": ".",
|
||||||
"paths": {
|
"paths": {
|
||||||
|
"@utils/*": ["src/utils/*"],
|
||||||
"@utils/test": ["src/utils/test/utils"]
|
"@utils/test": ["src/utils/test/utils"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|