diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 5593984949..36964ddc1f 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -53,6 +53,13 @@ jobs: name: dev-pages-react${{ matrix.react }} path: pages/lib/static-default + - name: Upload test utils selectors artifact + if: matrix.react == 18 + uses: actions/upload-artifact@v4 + with: + name: test-utils-selectors + path: lib/components + deploy: needs: quick-build name: deploy${{ matrix.react != 16 && format(' (React {0})', matrix.react) || '' }} @@ -65,3 +72,14 @@ jobs: with: artifact-name: dev-pages-react${{ matrix.react }} deployment-path: pages/lib/static-default + + visual: + name: Visual regression + needs: quick-build + if: ${{ github.event.pull_request.head.repo.full_name == github.repository }} + uses: ./.github/workflows/visual-regression.yml + secrets: inherit + with: + pr-artifact-name: dev-pages-react18 + test-utils-artifact-name: test-utils-selectors + caller-run-id: ${{ github.run_id }} diff --git a/.github/workflows/visual-regression.yml b/.github/workflows/visual-regression.yml new file mode 100644 index 0000000000..9e6d300d91 --- /dev/null +++ b/.github/workflows/visual-regression.yml @@ -0,0 +1,194 @@ +name: Visual Regression Tests + +on: + workflow_call: + inputs: + pr-artifact-name: + description: 'Name of the artifact containing PR pages (built by the caller workflow).' + required: true + type: string + test-utils-artifact-name: + description: 'Name of the artifact containing test-utils selectors.' + required: true + type: string + caller-run-id: + description: 'The run ID of the calling workflow, used to download artifacts it uploaded.' + required: true + type: string + +defaults: + run: + shell: bash + +permissions: + id-token: write + contents: read + actions: read + deployments: write + +jobs: + # Build the baseline (main branch) pages once and share them across all browser jobs. + build-baseline: + name: Build baseline pages + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: npm + + - name: Install dependencies + run: npm i + + # Use a git worktree so the baseline has its own directory and its own + # node_modules. This means a PR that changes package-lock.json will still + # produce a correct baseline: the baseline installs from main's lockfile + # and the PR build installs from the PR's lockfile, so both sides use the + # dependency versions that are correct for their respective source trees. + - name: Create baseline worktree from origin/main + run: git worktree add /tmp/baseline origin/main + + - name: Install baseline dependencies + run: npm i + working-directory: /tmp/baseline + + - name: Build baseline pages + run: npx gulp quick-build + working-directory: /tmp/baseline + env: + NODE_ENV: production + + - name: Bundle baseline pages + run: node_modules/.bin/webpack --config pages/webpack.config.integ.cjs --output-path ${{ github.workspace }}/pages/lib/static-visual-baseline + working-directory: /tmp/baseline + env: + NODE_ENV: production + + - name: Upload baseline artifact + uses: actions/upload-artifact@v4 + with: + name: visual-baseline-pages + path: pages/lib/static-visual-baseline + retention-days: 1 + + visual: + name: Visual regression (shard ${{ matrix.shard }}) + needs: [build-baseline] + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + shard: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40] + steps: + - uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: npm + + - name: Set up Chrome and ChromeDriver + uses: browser-actions/setup-chrome@v1 + with: + chrome-version: stable + + - name: Install dependencies + run: npm i + + - name: Download PR pages artifact + uses: actions/download-artifact@v4 + with: + name: ${{ inputs.pr-artifact-name }} + path: pages/lib/static-default + github-token: ${{ github.token }} + run-id: ${{ inputs.caller-run-id }} + + - name: Download baseline artifact + uses: actions/download-artifact@v4 + with: + name: visual-baseline-pages + path: pages/lib/static-visual-baseline + + - name: Download test utils artifact + uses: actions/download-artifact@v4 + with: + name: ${{ inputs.test-utils-artifact-name }} + path: lib/components + github-token: ${{ github.token }} + run-id: ${{ inputs.caller-run-id }} + + # ── Run tests ───────────────────────────────────────────────────────── + + - name: Start test server (port 8080) + run: npx --yes serve --no-clipboard --listen 8080 pages/lib/static-default & + + - name: Start baseline server (port 8081) + run: npx --yes serve --no-clipboard --listen 8081 pages/lib/static-visual-baseline & + + - name: Wait for servers to be ready + run: node_modules/.bin/wait-on http://localhost:8080 http://localhost:8081 + + - name: Run visual regression tests + run: NODE_OPTIONS=--experimental-vm-modules node_modules/.bin/jest -c jest.visual.config.js --shard=${{ matrix.shard }}/40 + env: + TZ: UTC + + - name: Upload diff artifacts + if: failure() + uses: actions/upload-artifact@v4 + with: + name: visual-regression-diffs-shard-${{ matrix.shard }} + path: visual-regression-output/ + retention-days: 14 + + - name: Upload Allure results + if: always() + uses: actions/upload-artifact@v4 + with: + name: allure-results-shard-${{ matrix.shard }} + path: allure-results/ + retention-days: 3 + + report: + name: Generate Allure Report + if: always() + needs: [visual] + runs-on: ubuntu-latest + steps: + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + + - name: Download all Allure results + uses: actions/download-artifact@v4 + with: + pattern: allure-results-shard-* + path: allure-results + merge-multiple: true + + - name: Generate Allure HTML report + run: npx --yes allure generate allure-results -o allure-report + + - name: Upload Allure report artifact + uses: actions/upload-artifact@v4 + with: + name: allure-report + path: allure-report/ + retention-days: 14 + + deploy-report: + name: Deploy Allure Report + if: always() + needs: [report] + uses: cloudscape-design/actions/.github/workflows/deploy.yml@main + secrets: inherit + with: + artifact-name: allure-report + deployment-path: allure-report diff --git a/.gitignore b/.gitignore index db3d62b944..9b14cf8ced 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,8 @@ coverage lib # generated sources src/index.ts +allure-results +allure-report src/test-utils/dom/index.ts src/test-utils/selectors src/icon/generated diff --git a/build-tools/tasks/package-json.js b/build-tools/tasks/package-json.js index a7c69a53f5..2c447682a1 100644 --- a/build-tools/tasks/package-json.js +++ b/build-tools/tasks/package-json.js @@ -103,6 +103,10 @@ const devPagesPackageJson = generatePackageJson(path.join(workspace.targetPath, const testDefinitionsPackageJson = generatePackageJson(path.join(workspace.targetPath, 'test-definitions'), { name: '@cloudscape-design/test-definitions', + exports: { + '.': './index.js', + './types': './types.js', + }, }); module.exports = parallel([ diff --git a/build-tools/visual/global-setup.js b/build-tools/visual/global-setup.js new file mode 100644 index 0000000000..52ce2f271c --- /dev/null +++ b/build-tools/visual/global-setup.js @@ -0,0 +1,7 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +module.exports = async () => { + const { startWebdriver } = require('@cloudscape-design/browser-test-tools/chrome-launcher'); + await startWebdriver(); +}; diff --git a/build-tools/visual/global-teardown.js b/build-tools/visual/global-teardown.js new file mode 100644 index 0000000000..0fa05eebfe --- /dev/null +++ b/build-tools/visual/global-teardown.js @@ -0,0 +1,7 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +module.exports = () => { + const { shutdownWebdriver } = require('@cloudscape-design/browser-test-tools/chrome-launcher'); + shutdownWebdriver(); +}; diff --git a/build-tools/visual/setup.js b/build-tools/visual/setup.js new file mode 100644 index 0000000000..d52cd606fb --- /dev/null +++ b/build-tools/visual/setup.js @@ -0,0 +1,16 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +/* global jest */ +const { configure } = require('@cloudscape-design/browser-test-tools/use-browser'); + +configure({ + browserName: 'ChromeHeadlessIntegration', + browserCreatorOptions: { + seleniumUrl: 'http://localhost:9515', + }, + webdriverOptions: { + baseUrl: 'http://localhost:8080', + }, +}); + +jest.retryTimes(2, { logErrorsBeforeRetry: true }); diff --git a/docs/RUNNING_TESTS.md b/docs/RUNNING_TESTS.md index 525cdf181d..4db82e361b 100644 --- a/docs/RUNNING_TESTS.md +++ b/docs/RUNNING_TESTS.md @@ -60,11 +60,60 @@ TZ=UTC npx jest -u -c jest.unit.config.js src/ ``` ## Visual Regression Tests -> **Note:** The components repository does not have visual regression tests on GitHub. This section applies to other repositories such as chat-components, code-view, chart-components, and board-components. +Visual regression tests run automatically when opening a pull request in GitHub (see `.github/workflows/visual-regression.yml`). -Visual regression tests for permutation pages run automatically when opening a pull request in GitHub. +They compare permutation pages between the PR build and a baseline build of `main`, both served locally in the same CI job. Each side installs from its own `package-lock.json` via a git worktree, so dependency changes in the PR are handled correctly and unpinned updates in sister repositories affect both sides equally. -To check results: look at the "Visual Regression Tests" action in the PR. The "Test for regressions" step logs which pages failed. For a full report, download the `visual-regression-snapshots-results` artifact from the action summary. +### How it works -If there are unexpected regressions, fix your pull request. -If the changes are expected, call this out in your pull request comments. +1. The PR pages are built and served on port 8080. +2. A git worktree of `origin/main` is created, its dependencies installed, and its pages built and served on port 8081. +3. The single test runner (`test/visual.test.ts`) iterates over all test definitions, captures the `.screenshot-area` element from both servers for each test, and fails if any pixels differ. + +### Running locally + +``` +npm run test:visual +``` + +This handles the full build and comparison in one command. If both outputs are already built, skip the build step: + +``` +NODE_OPTIONS=--experimental-vm-modules node_modules/.bin/jest -c jest.visual.config.js +``` + +(Requires both servers to be running — start the PR build with `npm run start:integ` on port 8080 and the baseline build on port 8081, or set `NEW_HOST` / `OLD_HOST` env vars to point at different hosts.) + +### Adding tests for a new component + +Create `test/definitions/visual/.ts`: + +```ts +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'my-component', + tests: [ + { + description: 'permutations', + path: 'my-component/permutations', + }, + ], +}; + +export default suite; +``` + +Then run the generation script to pick it up automatically: + +```bash +node build-tools/visual/generate-tests.js +``` + +This generates both the test runner (`test/visual/my-component.test.ts`) and updates `test/definitions/index.ts`. No manual imports needed. + +### Reviewing failures + +If the CI job fails, download the `visual-regression-diffs` artifact from the Actions summary. + +If the diff is expected (intentional visual change), note it in your PR description. diff --git a/eslint.config.mjs b/eslint.config.mjs index 0d9423aa5b..b92a169696 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -225,7 +225,7 @@ export default tsEslint.config( }, }, { - files: ['**/__integ__/**', '**/__motion__/**', '**/__a11y__/**'], + files: ['**/__integ__/**', '**/__motion__/**', '**/__a11y__/**', 'test/definitions/**'], rules: { // useBrowser is not a hook 'react-hooks/rules-of-hooks': 'off', diff --git a/jest.visual.config.js b/jest.visual.config.js new file mode 100644 index 0000000000..98938768b3 --- /dev/null +++ b/jest.visual.config.js @@ -0,0 +1,28 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +const path = require('path'); +const os = require('os'); + +module.exports = { + verbose: true, + testEnvironment: 'allure-jest/node', + testEnvironmentOptions: { + resultsDir: 'allure-results', + }, + transform: { + '^.+\\.tsx?$': [ + 'ts-jest', + { + tsconfig: 'tsconfig.visual.json', + }, + ], + }, + reporters: ['default', 'github-actions'], + testTimeout: 240_000, // 4min — pages can be tall and slow to capture + maxWorkers: os.cpus().length * (process.env.GITHUB_ACTION ? 3 : 1), + globalSetup: '/build-tools/visual/global-setup.js', + globalTeardown: '/build-tools/visual/global-teardown.js', + setupFilesAfterEnv: [path.join(__dirname, 'build-tools', 'visual', 'setup.js')], + moduleFileExtensions: ['js', 'ts'], + testMatch: ['/test/visual/**/*.test.ts'], +}; diff --git a/package-lock.json b/package-lock.json index c4d0123dfc..8dde4a72c8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -52,6 +52,7 @@ "@types/jest": "^29.5.13", "@types/lodash": "^4.14.176", "@types/node": "^20.17.14", + "@types/pixelmatch": "^5.2.6", "@types/react": "^16.14.20", "@types/react-dom": "^16.9.14", "@types/react-is": "^18.2.0", @@ -60,6 +61,7 @@ "@types/react-test-renderer": "^16.9.12", "@types/react-transition-group": "^4.4.4", "@types/webpack-env": "^1.16.3", + "allure-jest": "^3.9.0", "axe-core": "^4.7.2", "babel-jest": "^29.7.0", "change-case": "^4.1.2", @@ -96,6 +98,7 @@ "mockdate": "^3.0.5", "npm-run-all": "^4.1.5", "prettier": "^3.6.1", + "puppeteer-core": "^24.43.1", "react": "^16.14.0", "react-dom": "^16.14.0", "react-dom18": "npm:react-dom@^18.3.1", @@ -124,6 +127,7 @@ "typescript": "^5.9.2", "typescript-eslint": "^8.44.0", "wait-on": "^8.0.2", + "webdriverio": "^9.28.0", "webpack": "^5.105.0", "webpack-cli": "^5.1.4", "webpack-dev-server": "^5.2.4" @@ -3521,9 +3525,9 @@ } }, "node_modules/@puppeteer/browsers": { - "version": "2.13.0", - "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.13.0.tgz", - "integrity": "sha512-46BZJYJjc/WwmKjsvDFykHtXrtomsCIrwYQPOP7VfMJoZY2bsDF9oROBABR3paDjDcmkUye1Pb1BqdcdiipaWA==", + "version": "2.13.2", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.13.2.tgz", + "integrity": "sha512-5EUZSUIc37H6aIXyWO0Z4y8NlF8NnjgmqeQgOGiswAU7pY0HOo16ho4+alIWmSfdZnjqBRawMsP3I5YqLSn6kw==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -4796,6 +4800,16 @@ "undici-types": "~6.21.0" } }, + "node_modules/@types/pixelmatch": { + "version": "5.2.6", + "resolved": "https://registry.npmjs.org/@types/pixelmatch/-/pixelmatch-5.2.6.tgz", + "integrity": "sha512-wC83uexE5KGuUODn6zkm9gMzTwdY5L0chiK+VrKcDfEjzxh1uadlWTvOmAbCpnM9zx/Ww3f8uKlYQVnO/TrqVg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/pngjs": { "version": "6.0.5", "dev": true, @@ -5317,15 +5331,15 @@ "peer": true }, "node_modules/@wdio/config": { - "version": "9.24.0", - "resolved": "https://registry.npmjs.org/@wdio/config/-/config-9.24.0.tgz", - "integrity": "sha512-rcHu0eG16rSEmHL0sEKDcr/vYFmGhQ5GOlmlx54r+1sgh6sf136q+kth4169s16XqviWGW3LjZbUfpTK29pGtw==", + "version": "9.28.0", + "resolved": "https://registry.npmjs.org/@wdio/config/-/config-9.28.0.tgz", + "integrity": "sha512-a2po2x0Gi0hNRCuqSYSAvgwC9RZsj1tH9mt4MeLk2hyJBQCyy9DjBBjwyd4AcnE11XhqVaIkMaIMBSRu2dJwLw==", "dev": true, "license": "MIT", "dependencies": { "@wdio/logger": "9.18.0", - "@wdio/types": "9.24.0", - "@wdio/utils": "9.24.0", + "@wdio/types": "9.28.0", + "@wdio/utils": "9.28.0", "deepmerge-ts": "^7.0.3", "glob": "^10.2.2", "import-meta-resolve": "^4.0.0", @@ -5336,9 +5350,9 @@ } }, "node_modules/@wdio/config/node_modules/brace-expansion": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.3.tgz", - "integrity": "sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", + "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", "dev": true, "license": "MIT", "dependencies": { @@ -5434,9 +5448,9 @@ } }, "node_modules/@wdio/protocols": { - "version": "9.24.0", - "resolved": "https://registry.npmjs.org/@wdio/protocols/-/protocols-9.24.0.tgz", - "integrity": "sha512-ozQKYddBLT4TRvU9J+fGrhVUtx3iDAe+KNCJcTDMFMxNSdDMR2xFQdNp8HLHypspk58oXTYCvz6ZYjySthhqsw==", + "version": "9.28.0", + "resolved": "https://registry.npmjs.org/@wdio/protocols/-/protocols-9.28.0.tgz", + "integrity": "sha512-bO9NeMCrtwfWI7q77GwfD68NlRNijnmwicW1OQ6p+7D3kZWEicfdhfvojPhjjf+e9XzqMDnUDGD5ni1lGMUBsg==", "dev": true, "license": "MIT" }, @@ -5452,9 +5466,9 @@ } }, "node_modules/@wdio/types": { - "version": "9.24.0", - "resolved": "https://registry.npmjs.org/@wdio/types/-/types-9.24.0.tgz", - "integrity": "sha512-PYYunNl8Uq1r8YMJAK6ReRy/V/XIrCSyj5cpCtR5EqCL6heETOORFj7gt4uPnzidfgbtMBcCru0LgjjlMiH1UQ==", + "version": "9.28.0", + "resolved": "https://registry.npmjs.org/@wdio/types/-/types-9.28.0.tgz", + "integrity": "sha512-75JPq39gifkPNqOSn5C4/A5ZSyXwF+dGr5jfsCubFN9Lk9dKBXfjdbWueSQNpJg0jmE6dVrbT7+9mnDNnO0HdQ==", "dev": true, "license": "MIT", "dependencies": { @@ -5465,15 +5479,15 @@ } }, "node_modules/@wdio/utils": { - "version": "9.24.0", - "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-9.24.0.tgz", - "integrity": "sha512-6WhtzC5SNCGRBTkaObX6A07Ofnnyyf+TQH/d/fuhZRqvBknrP4AMMZF+PFxGl1fwdySWdBn+gV2QLE+52Byowg==", + "version": "9.28.0", + "resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-9.28.0.tgz", + "integrity": "sha512-VDqUaXpR8oOZSs26dy06Y2LhmA8bldsXDHeZ36n8SfW+Bq0miG0RRxou7aqx7sifVbbsuxrbBPXvmK+40uAIbQ==", "dev": true, "license": "MIT", "dependencies": { "@puppeteer/browsers": "^2.2.0", "@wdio/logger": "9.18.0", - "@wdio/types": "9.24.0", + "@wdio/types": "9.28.0", "decamelize": "^6.0.0", "deepmerge-ts": "^7.0.3", "edgedriver": "^6.1.2", @@ -5673,9 +5687,9 @@ "license": "Apache-2.0" }, "node_modules/@zip.js/zip.js": { - "version": "2.8.21", - "resolved": "https://registry.npmjs.org/@zip.js/zip.js/-/zip.js-2.8.21.tgz", - "integrity": "sha512-fkyzXISE3IMrstDO1AgPkJCx14MYHP/suIGiAovEYEuBjq3mffsuL6aMV7ohOSjW4rXtuACuUfpA3GtITgdtYg==", + "version": "2.8.26", + "resolved": "https://registry.npmjs.org/@zip.js/zip.js/-/zip.js-2.8.26.tgz", + "integrity": "sha512-RQ4h9F6DOiHxpdocUDrOl6xBM+yOtz+LkUol47AVWcfebGBDpZ7w7Xvz9PS24JgXvLGiXXzSAfdCdVy1tPlaFA==", "dev": true, "license": "BSD-3-Clause", "engines": { @@ -5842,6 +5856,58 @@ "dev": true, "license": "MIT" }, + "node_modules/allure-jest": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/allure-jest/-/allure-jest-3.9.0.tgz", + "integrity": "sha512-hEW4DKjvb3engGoHUPQaDEdyrFkUxQnqULiSQAehL1eDEggqdPbQro86Nch8Cj1yuIqUTn9UP1FMuuuwl/5jnQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "allure-js-commons": "3.9.0" + }, + "peerDependencies": { + "jest": ">=24.8.0", + "jest-circus": ">=24.8.0", + "jest-cli": ">=24.8.0", + "jest-environment-jsdom": ">=24.8.0", + "jest-environment-node": ">=24.8.0" + }, + "peerDependenciesMeta": { + "jest": { + "optional": true + }, + "jest-circus": { + "optional": true + }, + "jest-cli": { + "optional": true + }, + "jest-environment-jsdom": { + "optional": true + }, + "jest-environment-node": { + "optional": true + } + } + }, + "node_modules/allure-js-commons": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/allure-js-commons/-/allure-js-commons-3.9.0.tgz", + "integrity": "sha512-uVQcGE6MWIvGR/zW1XEUwHXUQa1EJKY0Cah+0TZK1qKuw6ptyhftDr34XE3wExTyCZirRrI98dbRtPeYYuyI+g==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "md5": "^2.3.0" + }, + "peerDependencies": { + "allure-playwright": "3.9.0" + }, + "peerDependenciesMeta": { + "allure-playwright": { + "optional": true + } + } + }, "node_modules/ansi-escapes": { "version": "4.3.2", "dev": true, @@ -7104,6 +7170,16 @@ "node": ">=10" } }, + "node_modules/charenc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", + "integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": "*" + } + }, "node_modules/cheerio": { "version": "1.1.0", "dev": true, @@ -7212,6 +7288,20 @@ "node": ">=6.0" } }, + "node_modules/chromium-bidi": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-14.0.0.tgz", + "integrity": "sha512-9gYlLtS6tStdRWzrtXaTMnqcM4dudNegMXJxkR0I/CXObHalYeYcAMPrL19eroNZHtJ8DQmu1E+ZNOYu/IXMXw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "mitt": "^3.0.1", + "zod": "^3.24.1" + }, + "peerDependencies": { + "devtools-protocol": "*" + } + }, "node_modules/ci-info": { "version": "3.9.0", "dev": true, @@ -7798,6 +7888,16 @@ "node": ">= 8" } }, + "node_modules/crypt": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", + "integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": "*" + } + }, "node_modules/css-declaration-sorter": { "version": "7.3.1", "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-7.3.1.tgz", @@ -8728,6 +8828,13 @@ "dev": true, "license": "MIT" }, + "node_modules/devtools-protocol": { + "version": "0.0.1608973", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1608973.tgz", + "integrity": "sha512-Tpm17fxYzt+J7VrGdc1k8YdRqS3YV7se/M6KeemEqvUbq/n7At1rWVuXMxQgpWkdwSdIEKYbU//Bve+Shm4YNQ==", + "dev": true, + "license": "BSD-3-Clause" + }, "node_modules/diff-sequences": { "version": "29.6.3", "dev": true, @@ -11232,9 +11339,9 @@ } }, "node_modules/get-port": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/get-port/-/get-port-7.1.0.tgz", - "integrity": "sha512-QB9NKEeDg3xxVwCCwJQ9+xycaz6pBB6iQ76wiWMl1927n0Kir6alPiP+yuiICLLU4jpMe08dXfpebuQppFA2zw==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-7.2.0.tgz", + "integrity": "sha512-afP4W205ONCuMoPBqcR6PSXnzX35KTcJygfJfcp+QY+uwm3p20p1YczWXhlICIzGMCxYBQcySEcOgsJcrkyobg==", "dev": true, "license": "MIT", "engines": { @@ -12509,6 +12616,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true, + "license": "MIT" + }, "node_modules/is-builtin-module": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-5.0.0.tgz", @@ -15188,6 +15302,18 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/md5": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz", + "integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "charenc": "0.0.2", + "crypt": "0.0.2", + "is-buffer": "~1.1.6" + } + }, "node_modules/mdn-data": { "version": "2.12.2", "dev": true, @@ -15472,9 +15598,9 @@ "license": "MIT" }, "node_modules/modern-tar": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/modern-tar/-/modern-tar-0.7.4.tgz", - "integrity": "sha512-5ixBi7pY+H8z3MKExsipXPq6S/Q27KpSY0K+NnIyLQLr58mNeZVhT9TkYcqa74H52DabOyrmGLhT5D7TZ/x26Q==", + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/modern-tar/-/modern-tar-0.7.6.tgz", + "integrity": "sha512-sweCIVXzx1aIGTCdzcMlSZt1h8k5Tmk08VNAuRk3IU28XamGiOH5ypi11g6De2CH7PhYqSSnGy2A/EFhbWnVKg==", "dev": true, "license": "MIT", "engines": { @@ -17685,6 +17811,25 @@ "node": ">=6" } }, + "node_modules/puppeteer-core": { + "version": "24.43.1", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-24.43.1.tgz", + "integrity": "sha512-T5ScUMAsmhdNbgDR41AGESYeS6V9MSgetkSnVhhW+gXvzC42VesKCn5ld87gAZDJ6vLHL9GkRvY9WtQWSnwFbw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@puppeteer/browsers": "2.13.2", + "chromium-bidi": "14.0.0", + "debug": "^4.4.3", + "devtools-protocol": "0.0.1608973", + "typed-query-selector": "^2.12.2", + "webdriver-bidi-protocol": "0.4.1", + "ws": "^8.20.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/pure-rand": { "version": "6.1.0", "dev": true, @@ -21099,6 +21244,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/typed-query-selector": { + "version": "2.12.2", + "resolved": "https://registry.npmjs.org/typed-query-selector/-/typed-query-selector-2.12.2.tgz", + "integrity": "sha512-EOPFbyIub4ngnEdqi2yOcNeDLaX/0jcE1JoAXQDDMIthap7FoN795lc/SHfIq2d416VufXpM8z/lD+WRm2gfOQ==", + "dev": true, + "license": "MIT" + }, "node_modules/typedarray": { "version": "0.0.6", "dev": true, @@ -21594,19 +21746,19 @@ } }, "node_modules/webdriver": { - "version": "9.24.0", - "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-9.24.0.tgz", - "integrity": "sha512-2R31Ey83NzMsafkl4hdFq6GlIBvOODQMkueLjeRqYAITu3QCYiq9oqBdnWA6CdePuV4dbKlYsKRX0mwMiPclDA==", + "version": "9.28.0", + "resolved": "https://registry.npmjs.org/webdriver/-/webdriver-9.28.0.tgz", + "integrity": "sha512-MmtC/n5rhOh/EYyYI1SbRBdEWctKaQouVeEAybv5SD/2bhTjg800q7mvGqHzhTXpqTPY5cdbOtT0PBdT89wz9w==", "dev": true, "license": "MIT", "dependencies": { "@types/node": "^20.1.0", "@types/ws": "^8.5.3", - "@wdio/config": "9.24.0", + "@wdio/config": "9.28.0", "@wdio/logger": "9.18.0", - "@wdio/protocols": "9.24.0", - "@wdio/types": "9.24.0", - "@wdio/utils": "9.24.0", + "@wdio/protocols": "9.28.0", + "@wdio/types": "9.28.0", + "@wdio/utils": "9.28.0", "deepmerge-ts": "^7.0.3", "https-proxy-agent": "^7.0.6", "undici": "^6.21.3", @@ -21616,6 +21768,13 @@ "node": ">=18.20.0" } }, + "node_modules/webdriver-bidi-protocol": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/webdriver-bidi-protocol/-/webdriver-bidi-protocol-0.4.1.tgz", + "integrity": "sha512-ARrjNjtWRRs2w4Tk7nqrf2gBI0QXWuOmMCx2hU+1jUt6d00MjMxURrhxhGbrsoiZKJrhTSTzbIrc554iKI10qw==", + "dev": true, + "license": "Apache-2.0" + }, "node_modules/webdriver/node_modules/agent-base": { "version": "7.1.4", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", @@ -21641,9 +21800,9 @@ } }, "node_modules/webdriver/node_modules/undici": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/undici/-/undici-6.24.1.tgz", - "integrity": "sha512-sC+b0tB1whOCzbtlx20fx3WgCXwkW627p4EA9uM+/tNNPkSS+eSEld6pAs9nDv7WbY1UUljBMYPtu9BCOrCWKA==", + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.26.0.tgz", + "integrity": "sha512-4yqz8a3n5HmGTlsbADNtr/dJlhkh/55Rq798G6ibiULcXbDtaLpTl1pvdqcbFfeoj3iSi52lePFM7h9H21cw/A==", "dev": true, "license": "MIT", "engines": { @@ -21651,20 +21810,20 @@ } }, "node_modules/webdriverio": { - "version": "9.24.0", - "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-9.24.0.tgz", - "integrity": "sha512-LTJt6Z/iDM0ne/4ytd3BykoPv9CuJ+CAILOzlwFeMGn4Mj02i4Bk2Rg9o/jeJ89f52hnv4OPmNjD0e8nzWAy5g==", + "version": "9.28.0", + "resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-9.28.0.tgz", + "integrity": "sha512-ieFWi8dq57uZC6QMC2x6TllxKTRyInIMcOrVvwbHqVRYvJP8OLDtlH1bideGRIN0pgGHWStqplez2A95jS9bqA==", "dev": true, "license": "MIT", "dependencies": { "@types/node": "^20.11.30", "@types/sinonjs__fake-timers": "^8.1.5", - "@wdio/config": "9.24.0", + "@wdio/config": "9.28.0", "@wdio/logger": "9.18.0", - "@wdio/protocols": "9.24.0", + "@wdio/protocols": "9.28.0", "@wdio/repl": "9.16.2", - "@wdio/types": "9.24.0", - "@wdio/utils": "9.24.0", + "@wdio/types": "9.28.0", + "@wdio/utils": "9.28.0", "archiver": "^7.0.1", "aria-query": "^5.3.0", "cheerio": "^1.0.0-rc.12", @@ -21681,7 +21840,7 @@ "rgb2hex": "0.2.5", "serialize-error": "^12.0.0", "urlpattern-polyfill": "^10.0.0", - "webdriver": "9.24.0" + "webdriver": "9.28.0" }, "engines": { "node": ">=18.20.0" @@ -22393,6 +22552,16 @@ "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } + }, + "node_modules/zod": { + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } } } } diff --git a/package.json b/package.json index 368682e67d..86a9f8e1a0 100644 --- a/package.json +++ b/package.json @@ -75,6 +75,7 @@ "@types/jest": "^29.5.13", "@types/lodash": "^4.14.176", "@types/node": "^20.17.14", + "@types/pixelmatch": "^5.2.6", "@types/react": "^16.14.20", "@types/react-dom": "^16.9.14", "@types/react-is": "^18.2.0", @@ -83,6 +84,7 @@ "@types/react-test-renderer": "^16.9.12", "@types/react-transition-group": "^4.4.4", "@types/webpack-env": "^1.16.3", + "allure-jest": "^3.9.0", "axe-core": "^4.7.2", "babel-jest": "^29.7.0", "change-case": "^4.1.2", @@ -119,6 +121,7 @@ "mockdate": "^3.0.5", "npm-run-all": "^4.1.5", "prettier": "^3.6.1", + "puppeteer-core": "^24.43.1", "react": "^16.14.0", "react-dom": "^16.14.0", "react-dom18": "npm:react-dom@^18.3.1", @@ -147,6 +150,7 @@ "typescript": "^5.9.2", "typescript-eslint": "^8.44.0", "wait-on": "^8.0.2", + "webdriverio": "^9.28.0", "webpack": "^5.105.0", "webpack-cli": "^5.1.4", "webpack-dev-server": "^5.2.4" diff --git a/src/select/__integ__/page-objects/select-page.ts b/src/select/__integ__/page-objects/select-page.ts index 38682eb564..26587fe536 100644 --- a/src/select/__integ__/page-objects/select-page.ts +++ b/src/select/__integ__/page-objects/select-page.ts @@ -36,7 +36,7 @@ export default class SelectPageObject< async selectOptionUsingDrag(optionNumber: number) { const triggerSelector = this.wrapper.findTrigger().toSelector(); // actions API does not work when element is not in the viewport - await (await this.browser.$(triggerSelector)).scrollIntoView(); + await this.browser.$(triggerSelector).scrollIntoView(); await this.buttonDownOnElement(triggerSelector); const { left, width, top, height } = await this.getBoundingBox( diff --git a/test/definitions/index.ts b/test/definitions/index.ts index 91e90a89f7..f870e6df76 100644 --- a/test/definitions/index.ts +++ b/test/definitions/index.ts @@ -1,10 +1,212 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -// Each component has its own test definition file. -// Import them here manually to form the full test suite. import { TestSuite } from './types'; +export { TestSuite, TestDefinition, ScreenshotType, ScreenshotTestConfiguration } from './types'; import actionCard from './visual/action-card'; import alert from './visual/alert'; +import appLayout from './visual/app-layout'; +import appLayoutContentPaddings from './visual/app-layout-content-paddings'; +import appLayoutDrawers from './visual/app-layout-drawers'; +import appLayoutFlashbar from './visual/app-layout-flashbar'; +import appLayoutHeader from './visual/app-layout-header'; +import appLayoutMulti from './visual/app-layout-multi'; +import appLayoutResponsive600 from './visual/app-layout-responsive-600'; +import appLayoutResponsive1280 from './visual/app-layout-responsive-1280'; +import appLayoutResponsive1400 from './visual/app-layout-responsive-1400'; +import appLayoutResponsive1920 from './visual/app-layout-responsive-1920'; +import appLayoutResponsive2540 from './visual/app-layout-responsive-2540'; +import appLayoutStickyTableHeaderSplitPanel from './visual/app-layout-sticky-table-header-split-panel'; +import appLayoutToolbar from './visual/app-layout-toolbar'; +import appLayoutZIndex from './visual/app-layout-z-index'; +import areaChart from './visual/area-chart'; +import attributeEditor from './visual/attribute-editor'; +import autosuggest from './visual/autosuggest'; +import badge from './visual/badge'; +import barChart from './visual/bar-chart'; +import box from './visual/box'; +import breadcrumbGroup from './visual/breadcrumb-group'; +import button from './visual/button'; +import buttonDropdown from './visual/button-dropdown'; +import buttonGroup from './visual/button-group'; +import cards from './visual/cards'; +import checkbox from './visual/checkbox'; +import codeEditor from './visual/code-editor'; +import collectionPreferences from './visual/collection-preferences'; +import columnLayout from './visual/column-layout'; +import container from './visual/container'; +import containerSticky from './visual/container-sticky'; +import contentLayout from './visual/content-layout'; +import contentLayoutPermutations from './visual/content-layout-permutations'; +import copyToClipboard from './visual/copy-to-clipboard'; +import dateInput from './visual/date-input'; +import datePicker from './visual/date-picker'; +import dateRangePicker from './visual/date-range-picker'; +import divider from './visual/divider'; +import drawer from './visual/drawer'; +import dropdown from './visual/dropdown'; +import expandableSection from './visual/expandable-section'; +import fileDropzone from './visual/file-dropzone'; +import fileInput from './visual/file-input'; +import fileTokenGroup from './visual/file-token-group'; +import fileUpload from './visual/file-upload'; +import flashbar from './visual/flashbar'; +import flashbarStacked from './visual/flashbar-stacked'; +import form from './visual/form'; +import formField from './visual/form-field'; +import grid from './visual/grid'; +import header from './visual/header'; +import helpPanel from './visual/help-panel'; +import icon from './visual/icon'; +import input from './visual/input'; +import itemCard from './visual/item-card'; +import keyValuePairs from './visual/key-value-pairs'; +import lineChart from './visual/line-chart'; +import link from './visual/link'; +import list from './visual/list'; +import mixedLineBarChart from './visual/mixed-line-bar-chart'; +import modal from './visual/modal'; +import multiselect from './visual/multiselect'; +import pagination from './visual/pagination'; +import pieChart from './visual/pie-chart'; +import popover from './visual/popover'; +import progressBar from './visual/progress-bar'; +import promptInput from './visual/prompt-input'; +import propertyFilter from './visual/property-filter'; +import radioButton from './visual/radio-button'; +import radioGroup from './visual/radio-group'; +import s3ResourceSelector from './visual/s3-resource-selector'; +import segmentedControl from './visual/segmented-control'; +import select from './visual/select'; +import sideNavigation from './visual/side-navigation'; +import slider from './visual/slider'; +import spaceBetween from './visual/space-between'; +import spinner from './visual/spinner'; +import splitPanel from './visual/split-panel'; +import statusIndicator from './visual/status-indicator'; +import steps from './visual/steps'; +import table from './visual/table'; +import tableCells from './visual/table-cells'; +import tableEmbedded from './visual/table-embedded'; +import tableInlineEditing from './visual/table-inline-editing'; +import tableResizableColumns from './visual/table-resizable-columns'; +import tableStickyHeader from './visual/table-sticky-header'; +import tableStickyScrollbar from './visual/table-sticky-scrollbar'; +import tabs from './visual/tabs'; +import tagEditor from './visual/tag-editor'; +import textContent from './visual/text-content'; +import textFilter from './visual/text-filter'; +import textarea from './visual/textarea'; +import tiles from './visual/tiles'; +import timeInput from './visual/time-input'; +import toggle from './visual/toggle'; +import toggleButton from './visual/toggle-button'; +import tokenGroup from './visual/token-group'; +import topNavigation from './visual/top-navigation'; +import treeView from './visual/tree-view'; +import wizard from './visual/wizard'; -export const allSuites: TestSuite[] = [actionCard, alert]; +export const allSuites: TestSuite[] = [ + actionCard, + alert, + appLayout, + appLayoutContentPaddings, + appLayoutDrawers, + appLayoutFlashbar, + appLayoutHeader, + appLayoutMulti, + appLayoutResponsive1280, + appLayoutResponsive1400, + appLayoutResponsive1920, + appLayoutResponsive2540, + appLayoutResponsive600, + appLayoutStickyTableHeaderSplitPanel, + appLayoutToolbar, + appLayoutZIndex, + areaChart, + attributeEditor, + autosuggest, + badge, + barChart, + box, + breadcrumbGroup, + button, + buttonDropdown, + buttonGroup, + cards, + checkbox, + codeEditor, + collectionPreferences, + columnLayout, + container, + containerSticky, + contentLayout, + contentLayoutPermutations, + copyToClipboard, + dateInput, + datePicker, + dateRangePicker, + divider, + drawer, + dropdown, + expandableSection, + fileDropzone, + fileInput, + fileTokenGroup, + fileUpload, + flashbar, + flashbarStacked, + form, + formField, + grid, + header, + helpPanel, + icon, + input, + itemCard, + keyValuePairs, + lineChart, + link, + list, + mixedLineBarChart, + modal, + multiselect, + pagination, + pieChart, + popover, + progressBar, + promptInput, + propertyFilter, + radioButton, + radioGroup, + s3ResourceSelector, + segmentedControl, + select, + sideNavigation, + slider, + spaceBetween, + spinner, + splitPanel, + statusIndicator, + steps, + table, + tableCells, + tableEmbedded, + tableInlineEditing, + tableResizableColumns, + tableStickyHeader, + tableStickyScrollbar, + tabs, + tagEditor, + textContent, + textFilter, + textarea, + tiles, + timeInput, + toggle, + toggleButton, + tokenGroup, + topNavigation, + treeView, + wizard, +]; diff --git a/test/definitions/instrumented-page-object.ts b/test/definitions/instrumented-page-object.ts new file mode 100644 index 0000000000..1851658e01 --- /dev/null +++ b/test/definitions/instrumented-page-object.ts @@ -0,0 +1,332 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +/** + * Instrumented ScreenshotPageObject that logs performance timings. + * Re-implements key methods to show which strategy is used and where time is spent. + */ +import pixelmatch from 'pixelmatch'; +import { PNG } from 'pngjs'; + +import { parsePng } from '@cloudscape-design/browser-test-tools/image-utils'; +import { ScreenshotPageObject, ScreenshotWithOffset } from '@cloudscape-design/browser-test-tools/page-objects'; + +type PermutationScreenshot = ScreenshotWithOffset & { id: string }; + +function ms(start: number): string { + return `${(performance.now() - start).toFixed(0)}ms`; +} + +export class InstrumentedPageObject extends ScreenshotPageObject { + private label = ''; + + setLabel(value: string) { + this.label = value; + } + + private log(msg: string) { + console.log(` ⏱ [${this.label}] ${msg}`); + } + + async captureViewport(): Promise { + const t0 = performance.now(); + + let t = performance.now(); + const { height, width } = await this.getViewportSize(); + this.log(` getViewportSize: ${ms(t)}`); + + t = performance.now(); + const rawBase64 = await this.browser.takeScreenshot(); + this.log(` takeScreenshot: ${ms(t)} (${(rawBase64.length / 1024).toFixed(0)}KB base64)`); + + t = performance.now(); + const image = await parsePng(rawBase64); + this.log(` parsePng: ${ms(t)}`); + + this.log(`captureViewport total: ${ms(t0)}`); + return { image, offset: { top: 0, left: 0 }, height, width } as ScreenshotWithOffset; + } + + async captureBySelector(selector: string, options: { viewportOnly?: boolean } = {}): Promise { + const t0 = performance.now(); + + let t = performance.now(); + await this.waitForVisible(selector); + this.log(` waitForVisible: ${ms(t)}`); + + t = performance.now(); + const { pixelRatio, top, left } = await this.getViewportSize(); + this.log(` getViewportSize: ${ms(t)}`); + + t = performance.now(); + const box = await this.getBoundingBox(selector); + this.log(` getBoundingBox: ${ms(t)}`); + + let rawBase64: string; + if (options.viewportOnly) { + t = performance.now(); + rawBase64 = await this.browser.takeScreenshot(); + this.log(` takeScreenshot (viewportOnly): ${ms(t)} (${(rawBase64.length / 1024).toFixed(0)}KB)`); + } else { + t = performance.now(); + rawBase64 = await this.fullPageScreenshotInstrumented(); + this.log(` fullPageScreenshot total: ${ms(t)} (${(rawBase64.length / 1024).toFixed(0)}KB)`); + } + + t = performance.now(); + const image = await parsePng(rawBase64); + this.log( + ` parsePng: ${ms(t)} (${image.width}x${image.height}px, ${(image.data.length / 1024 / 1024).toFixed(1)}MB raw)` + ); + + const offset = { top: box.top, left: box.left }; + if (!options.viewportOnly) { + offset.top += top; + offset.left += left; + } + + this.log(`captureBySelector total: ${ms(t0)}`); + return { image, offset, pixelRatio, height: box.height, width: box.width } as ScreenshotWithOffset; + } + + async capturePermutations(): Promise { + const t0 = performance.now(); + + let t = performance.now(); + await this.windowScrollTo({ top: 0, left: 0 }); + this.log(` windowScrollTo(0): ${ms(t)}`); + + // fitWindowHeightToContent + t = performance.now(); + const originalWindowSize = await this.browser.getWindowSize(); + const { viewportHeight, pageHeight } = await (this.browser as any).execute(function () { + return { + viewportHeight: window.innerHeight, + pageHeight: document.documentElement.scrollHeight, + }; + }); + const windowUIHeight = originalWindowSize.height - viewportHeight; + const targetHeight = pageHeight + windowUIHeight; + await this.browser.setWindowSize(originalWindowSize.width, targetHeight); + this.log(` fitWindowHeightToContent: ${ms(t)} (pageHeight=${pageHeight}, targetWindowHeight=${targetHeight})`); + + // getPermutationSizes + t = performance.now(); + const permutations: Array<{ id: string; width: number; height: number; offset: { top: number; left: number } }> = + await (this.browser as any).execute(function () { + const elements = document.querySelectorAll('[data-testid="permutation"]'); + return Array.from(elements).map(function (el: Element) { + const rect = el.getBoundingClientRect(); + return { + id: el.getAttribute('data-permutation-id') || rect.top + '-' + rect.left, + width: rect.width, + height: rect.height, + offset: { top: rect.top, left: rect.left }, + }; + }); + }); + this.log(` getPermutationSizes: ${ms(t)} (${permutations.length} found)`); + + if (permutations.length === 0) { + throw new Error('No permutations found on current page.'); + } + + // fullPageScreenshot + t = performance.now(); + const rawBase64 = await this.fullPageScreenshotInstrumented(); + this.log(` fullPageScreenshot: ${ms(t)} (${(rawBase64.length / 1024).toFixed(0)}KB)`); + + // parsePng + t = performance.now(); + const image = await parsePng(rawBase64); + this.log( + ` parsePng: ${ms(t)} (${image.width}x${image.height}px, ${(image.data.length / 1024 / 1024).toFixed(1)}MB raw pixels)` + ); + + // restore window size + t = performance.now(); + await this.browser.setWindowSize(originalWindowSize.width, originalWindowSize.height); + this.log(` restoreWindowSize: ${ms(t)}`); + + this.log(`capturePermutations total: ${ms(t0)}`); + return permutations.map(permutation => ({ ...permutation, image }) as PermutationScreenshot); + } + + /** + * Instrumented fullPageScreenshot that logs which strategy is selected. + */ + private async fullPageScreenshotInstrumented(): Promise { + const scrollPosition = await this.getWindowScroll(); + await this.waitForJsTimers(); + + const browserName = (this.browser.capabilities as any)?.browserName || ''; + if (browserName.toLowerCase().includes('firefox')) { + this.log(` strategy: scroll-and-merge (Firefox detected)`); + const result = await super.fullPageScreenshot(); + return result; + } + + // Try Puppeteer + let t = performance.now(); + let puppeteer: any = null; + try { + puppeteer = await (this.browser as any).getPuppeteer(); + } catch (e: any) { + this.log(` getPuppeteer failed: ${e.message?.substring(0, 80)}`); + } + const getPuppeteerTime = performance.now() - t; + + if (puppeteer && !this.forceScrollAndMerge) { + this.log(` strategy: PUPPETEER (getPuppeteer: ${getPuppeteerTime.toFixed(0)}ms)`); + t = performance.now(); + const image = await (this.browser as any).call(async () => { + const [current] = await puppeteer.pages(); + return current.screenshot({ fullPage: true, encoding: 'base64' }); + }); + this.log(` puppeteer.screenshot: ${ms(t)}`); + await this.windowScrollTo(scrollPosition); + return image as string; + } + + this.log( + ` strategy: SCROLL-AND-MERGE (puppeteer=${!!puppeteer}, forceScrollAndMerge=${this.forceScrollAndMerge}, getPuppeteer: ${getPuppeteerTime.toFixed(0)}ms)` + ); + // Delegate to parent which implements the scroll-and-merge properly + const result = await super.fullPageScreenshot(); + return result; + } +} + +// ─── Instrumented cropAndCompare ────────────────────────────────────────────── + +interface CropAndCompareResult { + firstImage: Buffer; + secondImage: Buffer; + diffImage: Buffer | null; + isEqual: boolean; + diffPixels: number; +} + +function cropImage(inImage: PNG, rect: { top: number; left: number; width: number; height: number }, pixelRatio = 1) { + const imageWidth = Math.ceil(rect.width * pixelRatio || inImage.width); + const imageHeight = Math.ceil(rect.height * pixelRatio || inImage.height); + const outImage = new PNG({ width: imageWidth, height: imageHeight }); + const safeLeft = Math.max(Math.round(rect.left), 0) * pixelRatio; + const safeTop = Math.max(Math.round(rect.top), 0) * pixelRatio; + const safeWidth = Math.min(imageWidth, inImage.width - safeLeft); + const safeHeight = Math.min(imageHeight, inImage.height - safeTop); + inImage.bitblt(outImage, safeLeft, safeTop, safeWidth, safeHeight, 0, 0); + return outImage; +} + +function packPng(png: PNG): Promise { + return new Promise((resolve, reject) => { + const chunks: Buffer[] = []; + const stream = png.pack(); + stream.on('data', (chunk: Buffer) => chunks.push(chunk)); + stream.on('end', () => resolve(Buffer.concat(chunks))); + stream.on('error', reject); + }); +} + +/** + * Instrumented cropAndCompare with per-step timing logs. + */ +export async function instrumentedCropAndCompare( + firstScreenshot: ScreenshotWithOffset, + secondScreenshot: ScreenshotWithOffset, + label = '' +): Promise { + const t0 = performance.now(); + const prefix = label ? `[${label}] ` : ''; + + // Fast path: raw base64 equality + const rawFirst = (firstScreenshot as any).rawBase64; + const rawSecond = (secondScreenshot as any).rawBase64; + if (rawFirst && rawSecond && rawFirst === rawSecond) { + const t = performance.now(); + const imageBuffer = Buffer.from(rawFirst, 'base64'); + console.log(` ⏱ ${prefix}cropAndCompare: ${ms(t0)} (FAST PATH: rawBase64 identical, decode: ${ms(t)})`); + return { firstImage: imageBuffer, secondImage: imageBuffer, diffImage: null, isEqual: true, diffPixels: 0 }; + } + + // Crop + const pixelRatio = firstScreenshot.pixelRatio || 1; + const size = { + height: Math.round(Math.max(firstScreenshot.height, secondScreenshot.height)), + width: Math.round(Math.max(firstScreenshot.width, secondScreenshot.width)), + }; + const scaledSize = { + width: Math.ceil(size.width * pixelRatio), + height: Math.ceil(size.height * pixelRatio), + }; + + let t = performance.now(); + const firstImage = cropImage( + firstScreenshot.image, + { top: firstScreenshot.offset.top, left: firstScreenshot.offset.left, width: size.width, height: size.height }, + pixelRatio + ); + const secondImage = cropImage( + secondScreenshot.image, + { top: secondScreenshot.offset.top, left: secondScreenshot.offset.left, width: size.width, height: size.height }, + pixelRatio + ); + console.log( + ` ⏱ ${prefix} crop (2 images): ${ms(t)} (${scaledSize.width}x${scaledSize.height}px, src: ${firstScreenshot.image.width}x${firstScreenshot.image.height}px)` + ); + + // Pixel comparison + t = performance.now(); + let diffPixels: number; + let diffImage: PNG | null = null; + if (scaledSize.width === 0 || scaledSize.height === 0) { + diffPixels = -1; + } else if (firstImage.data.equals(secondImage.data)) { + diffPixels = 0; + console.log(` ⏱ ${prefix} compareImages: ${ms(t)} (FAST: pixel buffers identical)`); + } else { + diffImage = new PNG({ width: scaledSize.width, height: scaledSize.height }); + diffPixels = pixelmatch(firstImage.data, secondImage.data, diffImage.data, scaledSize.width, scaledSize.height, { + threshold: 0.01, + }); + console.log(` ⏱ ${prefix} pixelmatch: ${ms(t)} (diffPixels=${diffPixels})`); + } + + // Pack PNGs — skip entirely when images are identical since we can use rawBase64 directly + t = performance.now(); + let firstPacked: Buffer; + let secondPacked: Buffer; + let diffPacked: Buffer | null = null; + + if (diffPixels === 0 && !diffImage) { + // Images are identical — use the raw screenshot PNG directly (it's already a valid PNG). + // This avoids the extremely expensive packPng re-encoding. + const rawFirst = (firstScreenshot as any).rawBase64; + if (rawFirst) { + firstPacked = Buffer.from(rawFirst, 'base64'); + secondPacked = firstPacked; + console.log(` ⏱ ${prefix} packPng SKIPPED (using rawBase64: ${(firstPacked.length / 1024).toFixed(0)}KB)`); + } else { + firstPacked = await packPng(firstImage); + secondPacked = firstPacked; + console.log(` ⏱ ${prefix} packPng (1 image, reused): ${ms(t)}`); + } + } else { + [firstPacked, secondPacked, diffPacked] = await Promise.all([ + packPng(firstImage), + packPng(secondImage), + diffImage ? packPng(diffImage) : Promise.resolve(null), + ]); + console.log(` ⏱ ${prefix} packPng (${diffImage ? 3 : 2} images): ${ms(t)}`); + } + + console.log(` ⏱ ${prefix}cropAndCompare total: ${ms(t0)} (diffPixels=${diffPixels})`); + return { + firstImage: firstPacked, + secondImage: secondPacked, + diffImage: diffPacked, + isEqual: diffPixels >= 0 && diffPixels <= 1, + diffPixels, + }; +} diff --git a/test/definitions/types.ts b/test/definitions/types.ts index 8cdca9996a..087fe2c52c 100644 --- a/test/definitions/types.ts +++ b/test/definitions/types.ts @@ -1,7 +1,13 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 +import { Browser } from 'webdriverio'; + import type { ScreenshotPageObject } from '@cloudscape-design/browser-test-tools/page-objects'; +import type createWrapper from '../../lib/components/test-utils/selectors'; + +export type Wrapper = ReturnType; + export interface ScreenshotTestConfiguration { width?: number; height?: number; @@ -9,7 +15,7 @@ export interface ScreenshotTestConfiguration { // 'screenshotArea' — captures the .screenshot-area element on the page. // 'permutations' — captures the entire page and crops permutations out of it. -export type ScreenshotType = 'screenshotArea' | 'permutations'; +export type ScreenshotType = 'screenshotArea' | 'permutations' | 'viewport'; export interface TestDefinition { description: string; @@ -17,7 +23,8 @@ export interface TestDefinition { screenshotType: ScreenshotType; queryParams?: Record; configuration?: ScreenshotTestConfiguration; - setup?: (page: ScreenshotPageObject) => Promise; + pixelDiffTolerance?: number; + setup?: ({ page, wrapper, browser }: { page: ScreenshotPageObject; wrapper: Wrapper; browser: Browser }) => void; } export interface TestSuite { diff --git a/test/definitions/utils.ts b/test/definitions/utils.ts new file mode 100644 index 0000000000..9be7f95075 --- /dev/null +++ b/test/definitions/utils.ts @@ -0,0 +1,253 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { attachment } from 'allure-js-commons'; + +import { cropAndCompare, parsePng } from '@cloudscape-design/browser-test-tools/image-utils'; +import { ScreenshotPageObject, ScreenshotWithOffset } from '@cloudscape-design/browser-test-tools/page-objects'; + +import createWrapper from '../../lib/components/test-utils/selectors'; +import { TestDefinition, TestSuite } from './types'; + +const screenshotAreaSelector = '.screenshot-area'; +const defaultWindowSize = { width: 1200, height: 800 }; + +// NEW_HOST serves the PR's pages, OLD_HOST serves the baseline (main) pages. +const newHost = process.env.NEW_HOST || 'http://localhost:8080'; +const oldHost = process.env.OLD_HOST || 'http://localhost:8081'; + +const wrapper = createWrapper(); + +// ─── Types ─────────────────────────────────────────────────────────────────── + +interface CropAndCompareResult { + firstImage: Buffer; + secondImage: Buffer; + diffImage: Buffer | null; + isEqual: boolean; + diffPixels: number; +} + +/** + * A raw screenshot that defers PNG decoding until needed. + * Allows fast byte-equality comparison on the compressed data. + */ +interface RawScreenshot { + rawBase64: string; + offset: { top: number; left: number }; + width: number; + height: number; + pixelRatio?: number; + id?: string; +} + +// ─── Helpers ───────────────────────────────────────────────────────────────── + +function buildUrl(host: string, path: string, queryParams?: Record): string { + const params = new URLSearchParams({ motionDisabled: 'true', ...queryParams }); + const qs = params.toString(); + return `${host}/#/${path}${qs ? `?${qs}` : ''}`; +} + +function isTestDefinition(item: TestDefinition | TestSuite): item is TestDefinition { + return (item as TestDefinition).path !== undefined; +} + +/** + * Attaches a visual comparison to the Allure report. + */ +async function attachDiffImages(result: CropAndCompareResult, testName: string): Promise { + const diffPayload = JSON.stringify({ + expected: `data:image/png;base64,${result.secondImage.toString('base64')}`, + actual: `data:image/png;base64,${result.firstImage.toString('base64')}`, + diff: result.diffImage ? `data:image/png;base64,${result.diffImage.toString('base64')}` : undefined, + }); + + await attachment(testName, diffPayload, 'application/vnd.allure.image.diff'); +} + +// ─── Capture functions ─────────────────────────────────────────────────────── + +/** + * Navigates to a URL, waits for the screenshot area, and runs setup. + */ +async function preparePage( + browser: WebdriverIO.Browser, + page: ScreenshotPageObject, + url: string, + testDef: TestDefinition, + windowSize?: { width?: number; height?: number } +): Promise { + await browser.setWindowSize( + windowSize?.width ?? defaultWindowSize.width, + windowSize?.height ?? defaultWindowSize.height + ); + await browser.url(url); + await page.waitForVisible(screenshotAreaSelector); + await page.waitForJsTimers(100); + if (testDef.setup) { + await testDef.setup({ page, wrapper, browser }); + } +} + +/** + * Captures a raw screenshot (base64 + metadata) WITHOUT decoding the PNG. + * This enables fast comparison on the compressed bytes. + */ +async function captureRaw( + browser: WebdriverIO.Browser, + page: ScreenshotPageObject, + testDef: TestDefinition +): Promise { + if (testDef.screenshotType === 'viewport') { + const { height, width } = await page.getViewportSize(); + const rawBase64 = await browser.takeScreenshot(); + return { rawBase64, offset: { top: 0, left: 0 }, width, height }; + } + + // screenshotArea or permutations: full-page screenshot with offset + const { pixelRatio } = await page.getViewportSize(); + const box = await page.getBoundingBox(screenshotAreaSelector); + const rawBase64 = await page.fullPageScreenshot(); + return { rawBase64, offset: { top: box.top, left: box.left }, width: box.width, height: box.height, pixelRatio }; +} + +/** + * Decodes a RawScreenshot into a ScreenshotWithOffset for cropAndCompare. + */ +async function decodeRaw(raw: RawScreenshot): Promise { + const image = await parsePng(raw.rawBase64); + return { image, offset: raw.offset, width: raw.width, height: raw.height, pixelRatio: raw.pixelRatio }; +} + +/** + * Compares two raw screenshots. If the compressed bytes are identical, + * skips the expensive parsePng + cropAndCompare pipeline entirely. + */ +async function compareScreenshots(newRaw: RawScreenshot, oldRaw: RawScreenshot): Promise { + // Fast path: identical compressed PNG bytes → images are the same. + if (newRaw.rawBase64 === oldRaw.rawBase64) { + const imageBuffer = Buffer.from(newRaw.rawBase64, 'base64'); + return { firstImage: imageBuffer, secondImage: imageBuffer, diffImage: null, isEqual: true, diffPixels: 0 }; + } + + // For element screenshots (taken via takeElementScreenshot with offset 0,0 and width 0), + // the PNG is already cropped — no decode/crop/re-encode needed. Just report the diff. + if (newRaw.width === 0 && newRaw.offset.top === 0 && newRaw.offset.left === 0) { + const firstImage = Buffer.from(newRaw.rawBase64, 'base64'); + const secondImage = Buffer.from(oldRaw.rawBase64, 'base64'); + return { firstImage, secondImage, diffImage: null, isEqual: false, diffPixels: 1 }; + } + + // Slow path: decode and do full pixel comparison. + const [newScreenshot, oldScreenshot] = await Promise.all([decodeRaw(newRaw), decodeRaw(oldRaw)]); + return cropAndCompare(newScreenshot, oldScreenshot); +} + +/** + * Captures each permutation element individually using takeElementScreenshot. + * Returns one raw base64 PNG per permutation — no decode, no crop, no re-encode. + */ +async function capturePermutationsRaw( + browser: WebdriverIO.Browser, + page: ScreenshotPageObject +): Promise { + await page.windowScrollTo({ top: 0, left: 0 }); + + // Find all permutation elements + const elements = await browser.$$('[data-permutation]'); + + if ((await elements.length) === 0) { + throw new Error('No permutations found on current page.'); + } + + // Take a screenshot of each permutation element directly via WebDriver. + // This returns a pre-cropped PNG for each element — no parsePng/packPng needed. + const results: RawScreenshot[] = []; + for (const element of elements) { + const id = (await element.getAttribute('data-permutation')) || ''; + const rawBase64 = await browser.takeElementScreenshot(element.elementId); + // offset/width/height are irrelevant since the screenshot is already cropped + results.push({ rawBase64, offset: { top: 0, left: 0 }, width: 0, height: 0, id }); + } + + return results; +} + +// ─── Test runner ───────────────────────────────────────────────────────────── + +export function runTestSuites(suites: Array) { + let browser: WebdriverIO.Browser; + + beforeAll(async () => { + const { default: getBrowserCreator } = await import('@cloudscape-design/browser-test-tools/browser'); + const creator = getBrowserCreator('ChromeHeadlessIntegration', 'local', { + seleniumUrl: 'http://localhost:9515', + }); + browser = await creator.getBrowser({ width: defaultWindowSize.width, height: defaultWindowSize.height }); + }); + + afterAll(async () => { + await browser?.deleteSession(); + }); + + registerSuites(suites, () => browser); +} + +function registerSuites(suites: Array, getBrowser: () => WebdriverIO.Browser) { + for (const item of suites) { + if (isTestDefinition(item)) { + registerTest(item, getBrowser); + } else { + describe(item.description, () => { + registerSuites(item.tests, getBrowser); + }); + } + } +} + +function registerTest(testDef: TestDefinition, getBrowser: () => WebdriverIO.Browser) { + test(testDef.description, async () => { + const tolerance = testDef.pixelDiffTolerance ?? 0; + const browser = getBrowser(); + const page = new ScreenshotPageObject(browser); + + const newUrl = buildUrl(newHost, testDef.path, testDef.queryParams); + const oldUrl = buildUrl(oldHost, testDef.path, testDef.queryParams); + + if (testDef.screenshotType === 'permutations') { + // Capture permutations as raw (no PNG decode) + await preparePage(browser, page, newUrl, testDef, testDef.configuration); + const newPerms = await capturePermutationsRaw(browser, page); + + await preparePage(browser, page, oldUrl, testDef, testDef.configuration); + const oldPerms = await capturePermutationsRaw(browser, page); + + expect(newPerms.length).toBe(oldPerms.length); + + // Compare each permutation individually and attach results. + const permFailures: number[] = []; + const attachmentPromises: Promise[] = []; + for (let i = 0; i < newPerms.length; i++) { + const permResult = await compareScreenshots(newPerms[i], oldPerms[i]); + attachmentPromises.push(attachDiffImages(permResult, `Permutation #${i.toString().padStart(3, '0')}`)); + if (permResult.diffPixels > tolerance) { + permFailures.push(i); + } + } + await Promise.all(attachmentPromises); + expect(permFailures).toEqual([]); + return; + } + + // Non-permutation: single screenshot comparison + await preparePage(browser, page, newUrl, testDef, testDef.configuration); + const newRaw = await captureRaw(browser, page, testDef); + + await preparePage(browser, page, oldUrl, testDef, testDef.configuration); + const oldRaw = await captureRaw(browser, page, testDef); + + const result = await compareScreenshots(newRaw, oldRaw); + await attachDiffImages(result, testDef.description); + expect(result.diffPixels).toBeLessThanOrEqual(tolerance); + }); +} diff --git a/test/definitions/visual/app-layout-content-paddings.ts b/test/definitions/visual/app-layout-content-paddings.ts new file mode 100644 index 0000000000..e76d055749 --- /dev/null +++ b/test/definitions/visual/app-layout-content-paddings.ts @@ -0,0 +1,30 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'Content paddings', + componentName: 'app-layout', + tests: [ + ...(['true', 'false'] as const).flatMap(toolsEnabled => + (['true', 'false'] as const).flatMap(splitPanelEnabled => + (['bottom', 'side'] as const).map(splitPanelPosition => ({ + description: `toolsEnabled=${toolsEnabled} splitPanelEnabled=${splitPanelEnabled} splitPanelPosition=${splitPanelPosition}`, + path: 'app-layout/with-split-panel', + screenshotType: 'viewport' as const, + queryParams: { toolsEnabled, splitPanelEnabled, splitPanelPosition }, + })) + ) + ), + ...[1500, 600].map(width => ({ + description: `with split panel and disabled content paddings - width=${width}`, + path: 'app-layout/disable-paddings-with-split-panel', + screenshotType: 'viewport' as const, + configuration: { width }, + queryParams: { splitPanelOpen: 'true', splitPanelPosition: 'side' }, + })), + ], +}; + +export default suite; diff --git a/test/definitions/visual/app-layout-drawers.ts b/test/definitions/visual/app-layout-drawers.ts new file mode 100644 index 0000000000..b9c97388a5 --- /dev/null +++ b/test/definitions/visual/app-layout-drawers.ts @@ -0,0 +1,38 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'Drawers', + componentName: 'app-layout', + tests: [ + { + description: 'with split panel', + path: 'app-layout/with-drawers', + screenshotType: 'viewport', + setup: async ({ page, wrapper }) => { + await page.click(wrapper.findAppLayout().findDrawerTriggerById('pro-help').toSelector()); + }, + }, + { + description: 'with tooltip on hover', + path: 'app-layout/with-drawers', + screenshotType: 'viewport', + setup: async ({ page, wrapper }) => { + await page.hoverElement(wrapper.findAppLayout().findDrawerTriggerById('pro-help').toSelector()); + }, + }, + { + description: 'with custom scrollable drawer content', + path: 'app-layout/with-drawers-scrollable', + screenshotType: 'viewport', + queryParams: { sideNavFill: 'false' }, + setup: async ({ page, wrapper }) => { + await page.click(wrapper.findAppLayout().findDrawerTriggerById('chat').toSelector()); + }, + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/app-layout-flashbar.ts b/test/definitions/visual/app-layout-flashbar.ts new file mode 100644 index 0000000000..bf402ebbed --- /dev/null +++ b/test/definitions/visual/app-layout-flashbar.ts @@ -0,0 +1,39 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'Flashbar', + componentName: 'app-layout', + tests: [true, false].flatMap(disableContentPaddings => + [true, false].flatMap(stickyNotifications => + [true, false].flatMap(stickyTableHeader => + [true, false].map(stackNotifications => ({ + description: `disableContentPaddings: ${disableContentPaddings}, stickyNotifications: ${stickyNotifications}, stickyTableHeader: ${stickyTableHeader}, stackNotifications: ${stackNotifications}`, + path: 'app-layout/with-stacked-notifications-and-table', + screenshotType: 'screenshotArea' as const, + configuration: { width: 1280, height: 900 }, + setup: async ({ page }) => { + if (!disableContentPaddings) { + await page.click('[data-id="toggle-content-paddings"]'); + } + if (stickyNotifications) { + await page.click('[data-id="toggle-sticky-notifications"]'); + } + if (!stickyTableHeader) { + await page.click('[data-id="toggle-sticky-table-header"]'); + } + if (!stackNotifications) { + await page.click('[data-id="toggle-stack-items"]'); + } + await page.click('[data-id="add-notification"]'); + await page.click('[data-id="add-notification"]'); + }, + })) + ) + ) + ), +}; + +export default suite; diff --git a/test/definitions/visual/app-layout-header.ts b/test/definitions/visual/app-layout-header.ts new file mode 100644 index 0000000000..e9d5fbac98 --- /dev/null +++ b/test/definitions/visual/app-layout-header.ts @@ -0,0 +1,85 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestDefinition, TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'Headers', + componentName: 'app-layout', + tests: [ + // ── Headers ─────────────────────────────────────────────────────────── + { + description: 'Headers', + tests: [600, 1280].flatMap(width => [ + { + description: `alignment with full-page table (${width}px)`, + path: 'app-layout/with-table', + screenshotType: 'viewport' as const, + configuration: { width }, + }, + { + description: `alignment with full-page table in sticky state (${width}px)`, + path: 'app-layout/with-table', + screenshotType: 'viewport' as const, + configuration: { width }, + setup: async ({ page }) => { + await page.windowScrollTo({ top: 200 }); + }, + }, + { + description: `alignment with full-page table in sticky state with sticky notifications (${width}px)`, + path: 'app-layout/with-table', + screenshotType: 'viewport' as const, + configuration: { width }, + queryParams: { stickyNotifications: 'true' }, + setup: async ({ page }) => { + await page.windowScrollTo({ top: 200 }); + }, + }, + { + description: `high contrast header variant in landing page (${width}px)`, + path: 'app-layout/landing-page', + screenshotType: 'viewport' as const, + configuration: { width }, + }, + ]), + }, + + // ── High contrast header variant ────────────────────────────────────── + { + description: 'High contrast header variant', + tests: [ + ...[1400, 600].flatMap(width => [ + { + description: `with breadcrumbs and notifications at ${width}px`, + path: 'app-layout/high-contrast-header-variant', + screenshotType: 'screenshotArea' as const, + configuration: { width }, + queryParams: { hasBreadcrumbs: 'true', hasNotifications: 'true', hasContainer: 'true' }, + } as TestDefinition, + { + description: `without overlap at ${width}px`, + path: 'app-layout/high-contrast-header-variant', + screenshotType: 'screenshotArea' as const, + configuration: { width }, + queryParams: { disableOverlap: 'true' }, + } as TestDefinition, + { + description: `with content layout at ${width}px`, + path: 'app-layout/high-contrast-header-variant', + screenshotType: 'screenshotArea' as const, + configuration: { width }, + queryParams: { + hasBreadcrumbs: 'true', + hasNotifications: 'true', + hasContainer: 'true', + hasContentLayout: 'true', + }, + } as TestDefinition, + ]), + ], + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/app-layout-multi.ts b/test/definitions/visual/app-layout-multi.ts new file mode 100644 index 0000000000..babf9733cf --- /dev/null +++ b/test/definitions/visual/app-layout-multi.ts @@ -0,0 +1,25 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'Multiple instances', + componentName: 'app-layout', + tests: [600, 1280].flatMap(width => [ + { + description: `simple (${width}px)`, + path: 'app-layout/multi-layout-simple', + screenshotType: 'viewport' as const, + configuration: { width }, + }, + { + description: `iframe (${width}px)`, + path: 'app-layout/multi-layout-iframe', + screenshotType: 'viewport' as const, + configuration: { width }, + }, + ]), +}; + +export default suite; diff --git a/test/definitions/visual/app-layout-responsive-1280.ts b/test/definitions/visual/app-layout-responsive-1280.ts new file mode 100644 index 0000000000..d5fe823f54 --- /dev/null +++ b/test/definitions/visual/app-layout-responsive-1280.ts @@ -0,0 +1,7 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { responsiveTests } from './app-layout-responsive-tests'; + +const suite = responsiveTests(1280); +export default suite; diff --git a/test/definitions/visual/app-layout-responsive-1400.ts b/test/definitions/visual/app-layout-responsive-1400.ts new file mode 100644 index 0000000000..1cb519005c --- /dev/null +++ b/test/definitions/visual/app-layout-responsive-1400.ts @@ -0,0 +1,7 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { responsiveTests } from './app-layout-responsive-tests'; + +const suite = responsiveTests(1400); +export default suite; diff --git a/test/definitions/visual/app-layout-responsive-1920.ts b/test/definitions/visual/app-layout-responsive-1920.ts new file mode 100644 index 0000000000..88b8c6caf3 --- /dev/null +++ b/test/definitions/visual/app-layout-responsive-1920.ts @@ -0,0 +1,7 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { responsiveTests } from './app-layout-responsive-tests'; + +const suite = responsiveTests(1920); +export default suite; diff --git a/test/definitions/visual/app-layout-responsive-2540.ts b/test/definitions/visual/app-layout-responsive-2540.ts new file mode 100644 index 0000000000..9dd62c00db --- /dev/null +++ b/test/definitions/visual/app-layout-responsive-2540.ts @@ -0,0 +1,7 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { responsiveTests } from './app-layout-responsive-tests'; + +const suite = responsiveTests(2540); +export default suite; diff --git a/test/definitions/visual/app-layout-responsive-600.ts b/test/definitions/visual/app-layout-responsive-600.ts new file mode 100644 index 0000000000..f6fd3665cc --- /dev/null +++ b/test/definitions/visual/app-layout-responsive-600.ts @@ -0,0 +1,7 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { responsiveTests } from './app-layout-responsive-tests'; + +const suite = responsiveTests(600); +export default suite; diff --git a/test/definitions/visual/app-layout-responsive-tests.ts b/test/definitions/visual/app-layout-responsive-tests.ts new file mode 100644 index 0000000000..2243f87a2a --- /dev/null +++ b/test/definitions/visual/app-layout-responsive-tests.ts @@ -0,0 +1,159 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +/** + * Shared responsive test scenarios for app-layout. Each width gets its own + * definition file and test runner so that Jest sharding can parallelize them. + */ +export function responsiveTests(width: number): TestSuite { + return { + description: `AppLayout responsive width ${width}px`, + componentName: 'app-layout', + tests: [ + { + description: 'default', + path: 'app-layout/default', + screenshotType: 'viewport', + configuration: { width }, + }, + { + description: 'navigation drawer is open', + path: 'app-layout/with-wizard', + screenshotType: 'viewport', + configuration: { width }, + setup: async ({ page }) => { + await page.click('[aria-label="Open navigation"]'); + }, + }, + { + description: 'wizard', + path: 'app-layout/with-wizard', + screenshotType: 'viewport', + configuration: { width }, + }, + { + description: 'with wizard and table', + path: 'app-layout/with-wizard-and-table', + screenshotType: 'viewport', + configuration: { width }, + }, + { + description: 'with wizard, table, and breadcrumbs', + path: 'app-layout/with-wizard-and-table', + screenshotType: 'viewport', + configuration: { width }, + queryParams: { hasBreadcrumbs: 'true' }, + }, + { + description: 'notifications', + path: 'app-layout/with-notifications', + screenshotType: 'viewport', + configuration: { width }, + }, + { + description: 'breadcrumbs', + path: 'app-layout/with-breadcrumbs', + screenshotType: 'viewport', + configuration: { width }, + }, + { + description: 'notifications and breadcrumbs', + path: 'app-layout/with-breadcrumbs-notifications', + screenshotType: 'viewport', + configuration: { width }, + }, + { + description: 'dashboard content type', + path: 'app-layout/dashboard-content-type', + screenshotType: 'viewport', + configuration: { width }, + }, + { + description: 'fixed header and footer', + path: 'app-layout/with-fixed-header-footer', + screenshotType: 'viewport', + configuration: { width }, + }, + { + description: 'disableBodyScroll - empty', + path: 'app-layout/legacy-nav-empty', + screenshotType: 'viewport', + configuration: { width }, + }, + { + description: 'disableBodyScroll - with content', + path: 'app-layout/legacy-nav-scrollable', + screenshotType: 'viewport', + configuration: { width }, + }, + { + description: 'disableBodyScroll - with split panel', + path: 'app-layout/legacy-nav-scrollable-with-split-panel', + screenshotType: 'viewport', + configuration: { width }, + }, + { + description: 'disable paddings', + path: 'app-layout/disable-paddings', + screenshotType: 'viewport', + configuration: { width }, + }, + { + description: 'disable paddings with breadcrumbs', + path: 'app-layout/disable-paddings-breadcrumbs', + screenshotType: 'viewport', + configuration: { width }, + }, + { + description: 'sticky notifications', + path: 'app-layout/with-sticky-notifications', + screenshotType: 'viewport', + configuration: { width }, + }, + { + description: 'sticky notifications scrolled down', + path: 'app-layout/with-sticky-notifications', + screenshotType: 'viewport', + configuration: { width }, + setup: async ({ page }) => { + await page.windowScrollTo({ top: 2000 }); + }, + }, + { + description: 'layout without panels', + path: 'app-layout/no-panels', + screenshotType: 'viewport', + configuration: { width }, + }, + { + description: 'layout without panels but with notifications', + path: 'app-layout/no-panels-with-notifications', + screenshotType: 'viewport', + configuration: { width }, + }, + { + description: 'with drawers', + path: 'app-layout/with-drawers', + screenshotType: 'viewport', + configuration: { width }, + }, + { + description: 'with empty drawers', + path: 'app-layout/with-drawers-empty', + screenshotType: 'viewport', + configuration: { width }, + }, + { + description: 'with open drawer', + path: 'app-layout/with-drawers', + screenshotType: 'viewport', + configuration: { width }, + setup: async ({ page }) => { + await page.click('[aria-label="Security trigger button"]'); + }, + }, + ], + }; +} diff --git a/test/definitions/visual/app-layout-sticky-table-header-split-panel.ts b/test/definitions/visual/app-layout-sticky-table-header-split-panel.ts new file mode 100644 index 0000000000..3bc920d22e --- /dev/null +++ b/test/definitions/visual/app-layout-sticky-table-header-split-panel.ts @@ -0,0 +1,78 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'Sticky header with split panel', + componentName: 'app-layout', + tests: [ + { + description: 'scrolling to bottom with closed split panel (1 table row)', + path: 'app-layout/with-sticky-table-and-split-panel', + screenshotType: 'viewport', + configuration: { width: 1280, height: 900 }, + setup: async ({ page }) => { + await page.click('[data-testid="set-item-count-to-1"]'); + await page.scrollToBottom('html'); + }, + }, + { + description: 'scrolling to bottom with closed split panel (30 table rows)', + path: 'app-layout/with-sticky-table-and-split-panel', + screenshotType: 'viewport', + configuration: { width: 1280, height: 900 }, + setup: async ({ page }) => { + await page.click('[data-testid="set-item-count-to-30"]'); + await page.scrollToBottom('html'); + }, + }, + { + description: 'header stays sticky with open split panel (1 table row)', + path: 'app-layout/with-sticky-table-and-split-panel', + screenshotType: 'viewport', + configuration: { width: 1280, height: 900 }, + setup: async ({ page }) => { + await page.click('[data-testid="set-item-count-to-1"]'); + await page.click('aria/Open panel'); + await page.scrollToBottom('html'); + }, + }, + { + description: 'header stays sticky with open split panel (30 table rows)', + path: 'app-layout/with-sticky-table-and-split-panel', + screenshotType: 'viewport', + configuration: { width: 1280, height: 900 }, + setup: async ({ page }) => { + await page.click('[data-testid="set-item-count-to-30"]'); + await page.click('aria/Open panel'); + await page.scrollToBottom('html'); + }, + }, + { + description: 'header stays sticky when mounting and unmounting a second table', + path: 'app-layout/with-sticky-table-and-split-panel', + screenshotType: 'viewport', + configuration: { width: 1280, height: 900 }, + setup: async ({ page }) => { + await page.click('[data-testid="set-item-count-to-30"]'); + await page.click('aria/Open panel'); + await page.windowScrollTo({ top: 0 }); + await page.click('aria/Close panel'); + await page.scrollToBottom('html'); + }, + }, + // ── Max content width ───────────────────────────────────────────────── + { + description: 'maxContentWidth set to Number.MAX_VALUE', + path: 'app-layout/refresh-content-width', + screenshotType: 'viewport', + configuration: { width: 1280, height: 700 }, + setup: async ({ page }) => { + await page.click('[data-test-id="button_width-number-max_value"]'); + }, + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/app-layout-toolbar.ts b/test/definitions/visual/app-layout-toolbar.ts new file mode 100644 index 0000000000..fb174b0a71 --- /dev/null +++ b/test/definitions/visual/app-layout-toolbar.ts @@ -0,0 +1,23 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'Toolbar', + componentName: 'app-layout', + tests: [ + { + description: 'multiple nested instances (no breadcrumbs dedup)', + path: 'app-layout-toolbar/multi-layout-with-hidden-instances', + screenshotType: 'viewport', + }, + { + description: 'no toolbar', + path: 'app-layout-toolbar/without-toolbar', + screenshotType: 'viewport', + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/app-layout-z-index.ts b/test/definitions/visual/app-layout-z-index.ts new file mode 100644 index 0000000000..149b2b8f36 --- /dev/null +++ b/test/definitions/visual/app-layout-z-index.ts @@ -0,0 +1,60 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestDefinition, TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'Z-index', + componentName: 'app-layout', + tests: [ + ...[600, 1280].flatMap(width => [ + { + description: `button dropdown (${width}px)`, + path: 'app-layout/with-absolute-components', + screenshotType: 'viewport' as const, + configuration: { width }, + setup: async ({ page }) => { + await page.click('button=Button dropdown'); + await page.click('[data-testid="2"]'); + await page.windowScrollTo({ top: 300 }); + }, + } as TestDefinition, + { + description: `select (${width}px)`, + path: 'app-layout/with-absolute-components', + screenshotType: 'viewport' as const, + configuration: { width, height: 800 }, + setup: async ({ page }) => { + await page.click('[data-testid="select-demo"] button'); + await page.windowScrollTo({ top: 300 }); + }, + } as TestDefinition, + { + description: `split-panel and full-page table (${width}px)`, + path: 'app-layout/with-full-page-table-and-split-panel', + screenshotType: 'viewport' as const, + configuration: { width }, + }, + ]), + { + description: 'split-panel and full-page with open navigation (600px)', + path: 'app-layout/with-full-page-table-and-split-panel', + screenshotType: 'viewport' as const, + configuration: { width: 600 }, + setup: async ({ page }) => { + await page.click('button[aria-label="Open navigation"]'); + }, + }, + { + description: 'split-panel and full-page with open tools (600px)', + path: 'app-layout/with-full-page-table-and-split-panel', + screenshotType: 'viewport' as const, + configuration: { width: 600 }, + setup: async ({ page }) => { + await page.click('button[aria-label="Open tools"]'); + }, + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/app-layout.ts b/test/definitions/visual/app-layout.ts new file mode 100644 index 0000000000..3a8453c47a --- /dev/null +++ b/test/definitions/visual/app-layout.ts @@ -0,0 +1,104 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'AppLayout', + componentName: 'app-layout', + tests: [ + { + description: 'no scrollbars at 320px', + path: 'app-layout/default', + screenshotType: 'viewport', + configuration: { width: 320 }, + }, + { + description: 'drawer buttons alignment', + path: 'app-layout/default', + screenshotType: 'viewport', + configuration: { width: 800 }, + setup: async ({ page }) => { + await page.click('[aria-label="Open tools"]'); + }, + }, + { + description: 'disable paddings - navigation closed', + path: 'app-layout/disable-paddings', + screenshotType: 'viewport', + configuration: { width: 1280 }, + setup: async ({ page }) => { + await page.click('[aria-label="Close navigation"]'); + }, + }, + { + description: 'panels stacking on mobile', + path: 'app-layout/all-panels-open', + screenshotType: 'viewport', + configuration: { width: 600 }, + }, + { + description: 'wrapping long words', + path: 'app-layout/text-wrap', + screenshotType: 'viewport', + }, + { + description: 'fill content area', + path: 'app-layout/fill-content-area', + screenshotType: 'viewport', + }, + { + description: 'with tools and drawers', + path: 'app-layout/with-drawers', + screenshotType: 'viewport', + queryParams: { hasTools: 'true' }, + }, + { + description: 'with open drawer and open side split panel', + path: 'app-layout/with-drawers', + screenshotType: 'viewport', + configuration: { width: 1400 }, + queryParams: { splitPanelPosition: 'side' }, + setup: async ({ page }) => { + await page.click('[aria-label="Security trigger button"]'); + await page.click('[aria-label="Open panel"]'); + }, + }, + + // regression for https://github.com/cloudscape-design/components/pull/1612 + { + description: 'with open drawer and open side split panel after resize', + path: 'app-layout/with-drawers', + screenshotType: 'viewport', + configuration: { width: 1500 }, + queryParams: { splitPanelPosition: 'side' }, + setup: async ({ page }) => { + await page.click('[aria-label="Security trigger button"]'); + await page.click('[aria-label="Open panel"]'); + await page.setWindowSize({ width: 1400, height: 800 }); + }, + }, + + // ── Transitions ─────────────────────────────────────────────────────── + { + description: 'transition from 400px to 1800px', + path: 'app-layout/default', + screenshotType: 'viewport', + configuration: { width: 400, height: 400 }, + setup: async ({ page }) => { + await page.setWindowSize({ width: 1800, height: 400 }); + }, + }, + { + description: 'transition from 1800px to 400px', + path: 'app-layout/default', + screenshotType: 'viewport', + configuration: { width: 1800, height: 400 }, + setup: async ({ page }) => { + await page.setWindowSize({ width: 400, height: 400 }); + }, + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/area-chart.ts b/test/definitions/visual/area-chart.ts new file mode 100644 index 0000000000..2d11756416 --- /dev/null +++ b/test/definitions/visual/area-chart.ts @@ -0,0 +1,136 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const TEST_CHART_FILTER_TRIGGER = '#linear-latency-chart button'; +const TEST_CHART_TOOLTIP_HEADER = '#linear-latency-chart h2'; + +const suite: TestSuite = { + description: 'Area chart', + componentName: 'area-chart', + tests: [ + { + description: 'permutations', + path: 'area-chart/permutations', + screenshotType: 'permutations', + }, + { + description: 'fit-height', + path: 'area-chart/fit-height', + screenshotType: 'screenshotArea', + }, + { + description: 'fit-height no filter, no legend', + path: 'area-chart/fit-height', + screenshotType: 'screenshotArea', + queryParams: { hideFilter: 'true', hideLegend: 'true' }, + }, + { + description: 'fit-height, no legend', + path: 'area-chart/fit-height', + screenshotType: 'screenshotArea', + queryParams: { hideLegend: 'true' }, + }, + { + description: 'chart plot has a focus outline', + path: 'area-chart/test', + screenshotType: 'viewport', + configuration: { width: 800, height: 800 }, + setup: async ({ page }) => { + await page.click(TEST_CHART_FILTER_TRIGGER); + await page.keys(['Escape']); + await page.focusNextElement(); + }, + }, + { + description: 'can navigate along X axis highlighting all series with keyboard', + path: 'area-chart/test', + screenshotType: 'viewport', + configuration: { width: 800, height: 800 }, + setup: async ({ page }) => { + await page.click(TEST_CHART_FILTER_TRIGGER); + await page.keys(['Escape']); + await page.focusNextElement(); + await page.keys(['ArrowRight', 'ArrowRight']); + await page.waitForVisible(TEST_CHART_TOOLTIP_HEADER); + }, + }, + { + description: 'can navigate a specific series with keyboard', + path: 'area-chart/test', + screenshotType: 'viewport', + configuration: { width: 800, height: 800 }, + setup: async ({ page }) => { + await page.click(TEST_CHART_FILTER_TRIGGER); + await page.keys(['Escape']); + await page.focusNextElement(); + await page.keys(['ArrowRight']); + await page.keys(['ArrowDown']); + await page.keys(['ArrowRight']); + await page.waitForVisible(TEST_CHART_TOOLTIP_HEADER); + }, + }, + { + description: 'selects correct series when navigated back from legend', + path: 'area-chart/test', + screenshotType: 'viewport', + configuration: { width: 800, height: 800 }, + setup: async ({ page }) => { + await page.click(TEST_CHART_FILTER_TRIGGER); + await page.keys(['Escape']); + await page.keys(['Tab']); + await page.keys(['Tab']); + await page.keys(['ArrowRight']); + await page.keys(['Shift', 'Tab']); + await page.keys(['ArrowRight']); + await page.waitForVisible(TEST_CHART_TOOLTIP_HEADER); + }, + }, + { + description: 'can pin popover for all data points at a given X coordinate with keyboard', + path: 'area-chart/test', + screenshotType: 'viewport', + configuration: { width: 800, height: 800 }, + setup: async ({ page }) => { + await page.click(TEST_CHART_FILTER_TRIGGER); + await page.keys(['Escape']); + await page.focusNextElement(); + await page.keys(['ArrowRight']); + await page.keys(['ArrowRight']); + await page.waitForVisible(TEST_CHART_TOOLTIP_HEADER); + await page.keys(['Enter']); + await page.waitForVisible('[aria-label="Dismiss"]'); + }, + }, + { + description: 'can pin popover for a point in a specific series with keyboard', + path: 'area-chart/test', + screenshotType: 'viewport', + configuration: { width: 800, height: 800 }, + setup: async ({ page }) => { + await page.click(TEST_CHART_FILTER_TRIGGER); + await page.keys(['Escape']); + await page.focusNextElement(); + await page.keys(['ArrowRight']); + await page.keys(['ArrowDown']); + await page.keys(['ArrowRight']); + await page.waitForVisible(TEST_CHART_TOOLTIP_HEADER); + await page.keys(['Enter']); + await page.waitForVisible('[aria-label="Dismiss"]'); + }, + }, + { + description: 'shows popover on hover', + path: 'area-chart/test', + screenshotType: 'viewport', + configuration: { width: 800, height: 800 }, + setup: async ({ page }) => { + await page.hoverElement('[aria-label="Linear latency chart"]', 200, 50); + await page.waitForVisible(TEST_CHART_TOOLTIP_HEADER); + }, + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/attribute-editor.ts b/test/definitions/visual/attribute-editor.ts new file mode 100644 index 0000000000..33da3fad86 --- /dev/null +++ b/test/definitions/visual/attribute-editor.ts @@ -0,0 +1,31 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'Attribute Editor', + componentName: 'attribute-editor', + tests: [360, 768, 992].flatMap(width => [ + { + description: `permutations at ${width}px`, + path: 'attribute-editor/permutations', + screenshotType: 'permutations' as const, + configuration: { width }, + }, + { + description: `customizable-footer at ${width}px`, + path: 'attribute-editor/customizable-footer', + screenshotType: 'screenshotArea' as const, + configuration: { width }, + }, + { + description: `with long select at ${width}px`, + path: 'attribute-editor/select-with-long-value', + screenshotType: 'screenshotArea' as const, + configuration: { width }, + }, + ]), +}; + +export default suite; diff --git a/test/definitions/visual/autosuggest.ts b/test/definitions/visual/autosuggest.ts new file mode 100644 index 0000000000..b93cdf3b8d --- /dev/null +++ b/test/definitions/visual/autosuggest.ts @@ -0,0 +1,67 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestDefinition, TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'Autosuggest', + componentName: 'autosuggest', + tests: [ + { + description: 'permutations', + path: 'autosuggest/permutations', + screenshotType: 'permutations', + setup: async ({ page }) => { + await page.click('input'); + }, + }, + { + description: 'permutations for async properties', + path: 'autosuggest/permutations-async', + screenshotType: 'permutations', + setup: async ({ page }) => { + await page.click('input'); + }, + }, + { + description: 'Displays options with groups correctly', + path: 'autosuggest/scenarios', + screenshotType: 'screenshotArea', + setup: async ({ page }) => { + await page.click('input'); + }, + }, + { + description: 'Correctly displays dropdown regions', + path: 'autosuggest/regions-scenarios', + screenshotType: 'screenshotArea', + setup: async ({ page }) => { + await page.click('input'); + }, + }, + { + description: 'Long virtual list - navigate to last item', + path: 'autosuggest/virtual-scroll', + screenshotType: 'screenshotArea', + setup: async ({ page, wrapper }) => { + await page.click(wrapper.findAutosuggest().findNativeInput().toSelector()); + await page.keys(['ArrowUp']); + }, + }, + ...[true, false].map( + virtualScroll => + ({ + description: `with custom renderOption (virtualScroll=${virtualScroll})`, + path: 'autosuggest/custom-render-option', + screenshotType: 'screenshotArea', + queryParams: { virtualScroll: String(virtualScroll) }, + setup: async ({ page, wrapper }) => { + await page.click(wrapper.findAutosuggest().findNativeInput().toSelector()); + await page.keys(['ArrowDown']); + }, + }) as TestDefinition + ), + ], +}; + +export default suite; diff --git a/test/definitions/visual/badge.ts b/test/definitions/visual/badge.ts new file mode 100644 index 0000000000..7d405ed843 --- /dev/null +++ b/test/definitions/visual/badge.ts @@ -0,0 +1,23 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'Badge', + componentName: 'badge', + tests: [ + { + description: 'permutation page', + path: 'badge/permutations', + screenshotType: 'permutations', + }, + { + description: 'style custom page', + path: 'badge/style-custom-types', + screenshotType: 'screenshotArea', + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/bar-chart.ts b/test/definitions/visual/bar-chart.ts new file mode 100644 index 0000000000..dde6ef5969 --- /dev/null +++ b/test/definitions/visual/bar-chart.ts @@ -0,0 +1,99 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const TEST_CHART_TOOLTIP_HEADER = '#chart'; + +const suite: TestSuite = { + description: 'Bar chart', + componentName: 'bar-chart', + tests: [ + { + description: 'Horizontal bars permutations', + path: 'bar-chart/horizontal-bars-permutations', + screenshotType: 'permutations', + }, + { + description: 'Horizontal stacked bars permutations', + path: 'bar-chart/horizontal-stacked-bars-permutations', + screenshotType: 'permutations', + }, + { + description: 'Other permutations', + path: 'bar-chart/other-permutations', + screenshotType: 'permutations', + }, + { + description: 'Threshold permutations', + path: 'bar-chart/threshold-permutations', + screenshotType: 'permutations', + }, + { + description: 'Vertical bars permutations', + path: 'bar-chart/vertical-bars-permutations', + screenshotType: 'permutations', + }, + { + description: 'Vertical stacked bars permutations', + path: 'bar-chart/vertical-stacked-bars-permutations', + screenshotType: 'permutations', + }, + { + description: 'can navigate series with keyboard', + path: 'bar-chart/test', + screenshotType: 'viewport', + configuration: { width: 800, height: 800 }, + pixelDiffTolerance: 12, + setup: async ({ page }) => { + await page.click('#focus-target'); + await page.focusNextElement(); + await page.focusNextElement(); + await page.keys(['ArrowRight', 'ArrowRight']); + await page.waitForVisible(TEST_CHART_TOOLTIP_HEADER); + }, + }, + { + description: 'can pin popover with keyboard', + path: 'bar-chart/test', + screenshotType: 'viewport', + configuration: { width: 800, height: 800 }, + pixelDiffTolerance: 10, + setup: async ({ page }) => { + await page.click('#focus-target'); + await page.focusNextElement(); + await page.focusNextElement(); + await page.keys(['ArrowRight', 'ArrowRight']); + await page.waitForVisible(TEST_CHART_TOOLTIP_HEADER); + await page.keys(['Enter']); + await page.waitForVisible('[aria-label="Dismiss"]'); + }, + }, + { + description: 'shows popover on hover', + path: 'bar-chart/test', + screenshotType: 'viewport', + configuration: { width: 800, height: 800 }, + setup: async ({ page }) => { + await page.hoverElement('#chart svg[aria-label="Bar chart"]'); + await page.waitForVisible(TEST_CHART_TOOLTIP_HEADER); + }, + }, + { + description: 'wrapping long series title 123', + path: 'bar-chart/test', + screenshotType: 'viewport', + configuration: { width: 800, height: 800 }, + setup: async ({ page }) => { + await page.scrollToBottom('html'); + await page.click('#focus-target-3'); + await page.focusNextElement(); + await page.focusNextElement(); + await page.keys(['ArrowRight', 'Enter']); + await page.waitForVisible('[aria-label="Dismiss"]'); + }, + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/box.ts b/test/definitions/visual/box.ts new file mode 100644 index 0000000000..0de10d4318 --- /dev/null +++ b/test/definitions/visual/box.ts @@ -0,0 +1,43 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'Box', + componentName: 'box', + tests: [ + { + description: 'variants permutations', + path: 'box/variants', + screenshotType: 'permutations', + }, + { + description: 'margins permutations', + path: 'box/margins', + screenshotType: 'permutations', + }, + { + description: 'paddings permutations', + path: 'box/paddings', + screenshotType: 'permutations', + }, + { + description: 'float and textAlign', + path: 'box/float-align', + screenshotType: 'permutations', + }, + { + description: 'with overrides to layout defaults', + path: 'box/elements-with-extra-defaults', + screenshotType: 'screenshotArea', + }, + { + description: 'with icons in content', + path: 'box/iconography', + screenshotType: 'screenshotArea', + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/breadcrumb-group.ts b/test/definitions/visual/breadcrumb-group.ts new file mode 100644 index 0000000000..cf5a3013d7 --- /dev/null +++ b/test/definitions/visual/breadcrumb-group.ts @@ -0,0 +1,46 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'BreadcrumbGroup', + componentName: 'breadcrumb-group', + tests: [ + { + description: 'layout at 300px', + path: 'breadcrumb-group/scenarios', + screenshotType: 'screenshotArea', + configuration: { width: 300 }, + }, + { + description: 'layout at 680px', + path: 'breadcrumb-group/scenarios', + screenshotType: 'screenshotArea', + configuration: { width: 680 }, + }, + { + description: 'layout at 1200px', + path: 'breadcrumb-group/scenarios', + screenshotType: 'screenshotArea', + configuration: { width: 1200 }, + }, + { + description: 'dropdown', + path: 'breadcrumb-group/scenarios', + screenshotType: 'viewport', + configuration: { width: 300, height: 1000 }, + setup: async ({ page, wrapper }) => { + await page.click(wrapper.findBreadcrumbGroup('[data-testid="breadcrumbs-6"]').findDropdown().toSelector()); + }, + }, + { + description: 'responsive behavior', + path: 'breadcrumb-group/responsive', + screenshotType: 'screenshotArea', + configuration: { width: 1200 }, + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/button-dropdown.ts b/test/definitions/visual/button-dropdown.ts new file mode 100644 index 0000000000..04c8c4c5c7 --- /dev/null +++ b/test/definitions/visual/button-dropdown.ts @@ -0,0 +1,395 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'ButtonDropdown', + componentName: 'button-dropdown', + tests: [ + { + description: 'ButtonDropdown opening top left at 500', + path: 'button-dropdown/scenarios-positioning', + screenshotType: 'viewport', + configuration: { width: 500 }, + setup: async ({ page }) => { + await page.click('.bd-top-left'); + }, + }, + { + description: 'ButtonDropdown opening top right at 500', + path: 'button-dropdown/scenarios-positioning', + screenshotType: 'viewport', + configuration: { width: 500 }, + setup: async ({ page }) => { + await page.click('.bd-top-right'); + }, + }, + { + description: 'ButtonDropdown opening bottom left at 500', + path: 'button-dropdown/scenarios-positioning', + screenshotType: 'viewport', + configuration: { width: 500 }, + setup: async ({ page }) => { + await page.click('.bd-bottom-left'); + }, + }, + { + description: 'ButtonDropdown opening bottom right at 500', + path: 'button-dropdown/scenarios-positioning', + screenshotType: 'viewport', + configuration: { width: 500 }, + setup: async ({ page }) => { + await page.click('.bd-bottom-right'); + }, + }, + { + description: 'ButtonDropdown opening top left at 800', + path: 'button-dropdown/scenarios-positioning', + screenshotType: 'viewport', + configuration: { width: 800 }, + setup: async ({ page }) => { + await page.click('.bd-top-left'); + }, + }, + { + description: 'ButtonDropdown opening top right at 800', + path: 'button-dropdown/scenarios-positioning', + screenshotType: 'viewport', + configuration: { width: 800 }, + setup: async ({ page }) => { + await page.click('.bd-top-right'); + }, + }, + { + description: 'ButtonDropdown opening bottom left at 800', + path: 'button-dropdown/scenarios-positioning', + screenshotType: 'viewport', + configuration: { width: 800 }, + setup: async ({ page }) => { + await page.click('.bd-bottom-left'); + }, + }, + { + description: 'ButtonDropdown opening bottom right at 800', + path: 'button-dropdown/scenarios-positioning', + screenshotType: 'viewport', + configuration: { width: 800 }, + setup: async ({ page }) => { + await page.click('.bd-bottom-right'); + }, + }, + { + description: 'ButtonDropdown opening top left, width maximum truncated', + path: 'button-dropdown/scenarios-positioning', + screenshotType: 'viewport', + configuration: { width: 230, height: 400 }, + setup: async ({ page }) => { + await page.click('.bd-top-left'); + }, + }, + { + description: 'ButtonDropdown opening bottom left, width maximum truncated', + path: 'button-dropdown/scenarios-positioning', + screenshotType: 'viewport', + configuration: { width: 230, height: 400 }, + setup: async ({ page }) => { + await page.click('.bd-bottom-left'); + }, + }, + { + description: 'ButtonDropdown with expandable groups opening top left at 500', + path: 'button-dropdown/scenarios-expandable', + screenshotType: 'viewport', + configuration: { width: 500 }, + setup: async ({ page }) => { + await page.click('.bd-top-left'); + await page.click('[data-testid="category1"]'); + }, + }, + { + description: 'ButtonDropdown with expandable groups opening top right at 500', + path: 'button-dropdown/scenarios-expandable', + screenshotType: 'viewport', + configuration: { width: 500 }, + setup: async ({ page }) => { + await page.click('.bd-top-right'); + await page.click('[data-testid="category1"]'); + }, + }, + { + description: 'ButtonDropdown with expandable groups opening bottom left at 500', + path: 'button-dropdown/scenarios-expandable', + screenshotType: 'viewport', + configuration: { width: 500 }, + setup: async ({ page }) => { + await page.click('.bd-bottom-left'); + await page.click('[data-testid="category1"]'); + }, + }, + { + description: 'ButtonDropdown with expandable groups opening bottom right at 500', + path: 'button-dropdown/scenarios-expandable', + screenshotType: 'viewport', + configuration: { width: 500 }, + setup: async ({ page }) => { + await page.click('.bd-bottom-right'); + await page.click('[data-testid="category1"]'); + }, + }, + { + description: 'ButtonDropdown with expandable groups opening top left at 1200', + path: 'button-dropdown/scenarios-expandable', + screenshotType: 'viewport', + configuration: { width: 1200 }, + setup: async ({ page }) => { + await page.click('.bd-top-left'); + await page.click('[data-testid="category1"]'); + }, + }, + { + description: 'ButtonDropdown with expandable groups opening top right at 1200', + path: 'button-dropdown/scenarios-expandable', + screenshotType: 'viewport', + configuration: { width: 1200 }, + setup: async ({ page }) => { + await page.click('.bd-top-right'); + await page.click('[data-testid="category1"]'); + }, + }, + { + description: 'ButtonDropdown with expandable groups opening bottom left at 1200', + path: 'button-dropdown/scenarios-expandable', + screenshotType: 'viewport', + configuration: { width: 1200 }, + setup: async ({ page }) => { + await page.click('.bd-bottom-left'); + await page.click('[data-testid="category1"]'); + }, + }, + { + description: 'ButtonDropdown with expandable groups opening bottom right at 1200', + path: 'button-dropdown/scenarios-expandable', + screenshotType: 'viewport', + configuration: { width: 1200 }, + setup: async ({ page }) => { + await page.click('.bd-bottom-right'); + await page.click('[data-testid="category1"]'); + }, + }, + { + description: 'ButtonDropdown in scrollable container', + path: 'button-dropdown/scenarios-container', + screenshotType: 'viewport', + configuration: { width: 600 }, + setup: async ({ page }) => { + await page.waitForVisible('#scrollable-container'); + const containerBBox = await page.getBoundingBox('#scrollable-container'); + const buttonBBox = await page.getBoundingBox('#ButtonDropdown button'); + await page.elementScrollTo('#scrollable-container', { + top: (containerBBox.height + buttonBBox.width) / 2, + left: (containerBBox.width + buttonBBox.width) / 2, + }); + await page.click('#ButtonDropdown'); + }, + }, + { + description: 'ButtonDropdown with expandToViewport overflowing a scroll container', + path: 'button-dropdown/scenarios-overflow-container', + screenshotType: 'viewport', + configuration: { width: 1000 }, + setup: async ({ page }) => { + await page.waitForVisible('#scroll-container'); + const containerBBox = await page.getBoundingBox('#scroll-container'); + const buttonBBox = await page.getBoundingBox('#button-dropdown-scroll button'); + await page.elementScrollTo('#scroll-container', { + top: (containerBBox.height + buttonBBox.width) / 2, + left: (containerBBox.width + buttonBBox.width) / 2, + }); + await page.click('#button-dropdown-scroll'); + await page.click('[data-testid="category1"]'); + }, + }, + { + description: 'ButtonDropdown with expandToViewport overflowing a hidden container', + path: 'button-dropdown/scenarios-overflow-container', + screenshotType: 'viewport', + configuration: { width: 1000 }, + setup: async ({ page }) => { + await page.waitForVisible('#hidden-container'); + await page.click('#button-dropdown-hidden'); + await page.click('[data-testid="category1"]'); + }, + }, + { + description: 'ButtonDropdown with expandToViewport overflowing an auto container', + path: 'button-dropdown/scenarios-overflow-container', + screenshotType: 'viewport', + configuration: { width: 1000 }, + setup: async ({ page }) => { + await page.waitForVisible('#auto-container'); + const containerBBox = await page.getBoundingBox('#auto-container'); + const buttonBBox = await page.getBoundingBox('#button-dropdown-auto button'); + await page.elementScrollTo('#auto-container', { + top: (containerBBox.height + buttonBBox.width) / 2, + left: (containerBBox.width + buttonBBox.width) / 2, + }); + await page.click('#button-dropdown-auto'); + await page.click('[data-testid="category1"]'); + }, + }, + { + description: 'ButtonDropdown permutations', + path: 'button-dropdown/permutations', + screenshotType: 'permutations', + }, + { + description: 'ButtonDropdown item element permutations', + path: 'button-dropdown/item-element.permutations', + screenshotType: 'permutations', + }, + { + description: 'ButtonDropdown main action permutations', + path: 'button-dropdown/permutations-main-action', + screenshotType: 'permutations', + }, + { + description: 'ButtonDropdown dimmed category group at width 500', + path: 'button-dropdown/simple', + screenshotType: 'screenshotArea', + setup: async ({ page }) => { + await page.click('#ButtonDropdown8'); + await page.keys(['ArrowDown', 'ArrowDown', 'Enter']); + }, + }, + { + description: 'ButtonDropdown dimmed category group at width 800', + path: 'button-dropdown/simple', + screenshotType: 'screenshotArea', + setup: async ({ page }) => { + await page.click('#ButtonDropdown8'); + await page.keys(['ArrowDown', 'ArrowDown', 'Enter']); + }, + }, + { + description: 'ButtonDropdown with disabled reason at width 500', + path: 'button-dropdown/disabled-reason', + screenshotType: 'screenshotArea', + setup: async ({ page }) => { + await page.click('[data-testid="buttonDropdown"]'); + await page.keys(['ArrowDown', 'ArrowDown', 'ArrowDown']); + }, + }, + { + description: 'ButtonDropdown with disabled reason at width 800', + path: 'button-dropdown/disabled-reason', + screenshotType: 'screenshotArea', + setup: async ({ page }) => { + await page.click('[data-testid="buttonDropdown"]'); + await page.keys(['ArrowDown', 'ArrowDown', 'ArrowDown']); + }, + }, + { + description: 'ButtonDropdown with disabled reason for selectable item at width 500', + path: 'button-dropdown/disabled-reason', + screenshotType: 'screenshotArea', + setup: async ({ page }) => { + await page.click('[data-testid="buttonDropdownSelectableItems"]'); + }, + }, + { + description: 'ButtonDropdown with disabled reason for selectable item at width 800', + path: 'button-dropdown/disabled-reason', + screenshotType: 'screenshotArea', + setup: async ({ page }) => { + await page.click('[data-testid="buttonDropdownSelectableItems"]'); + }, + }, + { + description: 'ButtonDropdown expandable groups show icons at width 500', + path: 'button-dropdown/icon-expandable', + screenshotType: 'screenshotArea', + configuration: { width: 500 }, + queryParams: { expandableGroups: 'true' }, + setup: async ({ page, wrapper }) => { + await page.click(wrapper.findButtonDropdown().toSelector()); + await page.click('[data-testid="category1"]'); + }, + }, + { + description: 'ButtonDropdown non-expandable groups show icons at width 500', + path: 'button-dropdown/icon-expandable', + screenshotType: 'screenshotArea', + configuration: { width: 500 }, + queryParams: { expandableGroups: 'false' }, + setup: async ({ page, wrapper }) => { + await page.click(wrapper.findButtonDropdown().toSelector()); + }, + }, + { + description: 'ButtonDropdown expandable groups show icons at width 800', + path: 'button-dropdown/icon-expandable', + screenshotType: 'screenshotArea', + configuration: { width: 800 }, + queryParams: { expandableGroups: 'true' }, + setup: async ({ page, wrapper }) => { + await page.click(wrapper.findButtonDropdown().toSelector()); + await page.click('[data-testid="category1"]'); + }, + }, + { + description: 'ButtonDropdown non-expandable groups show icons at width 800', + path: 'button-dropdown/icon-expandable', + screenshotType: 'screenshotArea', + configuration: { width: 800 }, + queryParams: { expandableGroups: 'false' }, + setup: async ({ page, wrapper }) => { + await page.click(wrapper.findButtonDropdown().toSelector()); + }, + }, + { + description: 'ButtonDropdown expandable groups with custom renderItem width 500', + path: 'button-dropdown/custom-render-item', + screenshotType: 'screenshotArea', + configuration: { width: 500 }, + queryParams: { expandableGroups: 'true' }, + setup: async ({ page, wrapper }) => { + await page.click(wrapper.findButtonDropdown().toSelector()); + await page.click('[data-testid="group"]'); + }, + }, + { + description: 'ButtonDropdown non-expandable groups with custom renderItem width 500', + path: 'button-dropdown/custom-render-item', + screenshotType: 'screenshotArea', + configuration: { width: 500 }, + queryParams: { expandableGroups: 'false' }, + setup: async ({ page, wrapper }) => { + await page.click(wrapper.findButtonDropdown().toSelector()); + }, + }, + { + description: 'ButtonDropdown expandable groups with custom renderItem width 1000', + path: 'button-dropdown/custom-render-item', + screenshotType: 'screenshotArea', + configuration: { width: 1000 }, + queryParams: { expandableGroups: 'true' }, + setup: async ({ page, wrapper }) => { + await page.click(wrapper.findButtonDropdown().toSelector()); + await page.click('[data-testid="group"]'); + }, + }, + { + description: 'ButtonDropdown non-expandable groups with custom renderItem width 1000', + path: 'button-dropdown/custom-render-item', + screenshotType: 'screenshotArea', + configuration: { width: 1000 }, + queryParams: { expandableGroups: 'false' }, + setup: async ({ page, wrapper }) => { + await page.click(wrapper.findButtonDropdown().toSelector()); + }, + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/button-group.ts b/test/definitions/visual/button-group.ts new file mode 100644 index 0000000000..839f19c19e --- /dev/null +++ b/test/definitions/visual/button-group.ts @@ -0,0 +1,52 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'ButtonGroup', + componentName: 'button-group', + tests: [ + { + description: 'item permutations', + path: 'button-group/item-permutations', + screenshotType: 'permutations', + }, + { + description: 'permutations', + path: 'button-group/permutations', + screenshotType: 'permutations', + }, + { + description: 'shows tooltip when hovering item', + path: 'button-group/test', + screenshotType: 'screenshotArea', + setup: async ({ page }) => { + await page.hoverElement('[data-testid="like"]'); + }, + }, + { + description: 'shows tooltip when hovering menu', + path: 'button-group/test', + screenshotType: 'screenshotArea', + setup: async ({ page }) => { + await page.hoverElement('[data-testid="more-actions"]'); + }, + }, + { + description: 'shows feedback when clicking copy', + path: 'button-group/test', + screenshotType: 'screenshotArea', + setup: async ({ page }) => { + await page.hoverElement('[data-testid="copy"]'); + }, + }, + { + description: 'style custom page', + path: 'button-group/style-custom-types', + screenshotType: 'screenshotArea', + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/button.ts b/test/definitions/visual/button.ts new file mode 100644 index 0000000000..b6b8645764 --- /dev/null +++ b/test/definitions/visual/button.ts @@ -0,0 +1,73 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'Button', + componentName: 'button', + tests: [ + { + description: 'permutations', + path: 'button/permutations', + screenshotType: 'permutations', + }, + { + description: 'style-permutations', + path: 'button/style-permutations', + screenshotType: 'permutations', + }, + { + description: 'style-custom-types', + path: 'button/style-custom-types', + screenshotType: 'screenshotArea', + }, + { + description: 'external', + path: 'button/external.permutations', + screenshotType: 'permutations', + }, + { + description: 'alignment', + path: 'button/alignment', + screenshotType: 'screenshotArea', + }, + { + description: 'wrapping text', + path: 'button/text-wrap', + screenshotType: 'screenshotArea', + }, + { + description: 'wrapping text with icon', + path: 'button/with-icon-wrap', + screenshotType: 'screenshotArea', + }, + { + description: 'Button is focused', + path: 'button/tab-navigation', + screenshotType: 'screenshotArea', + setup: async ({ page }) => { + await page.click('#focusButton'); + await page.focusNextElement(); + }, + }, + { + description: 'shows disabled reason tooltip on hover within modal', + path: 'button/disabled-reason-modal', + screenshotType: 'screenshotArea', + setup: async ({ page }) => { + await page.hoverElement('[data-testid="button"]'); + }, + }, + { + description: 'shows disabled reason tooltip on hover over a button with an href', + path: 'button/disabled-reason', + screenshotType: 'screenshotArea', + setup: async ({ page }) => { + await page.hoverElement('[data-testid="normal-button-with-href"]'); + }, + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/cards.ts b/test/definitions/visual/cards.ts new file mode 100644 index 0000000000..25227eedb1 --- /dev/null +++ b/test/definitions/visual/cards.ts @@ -0,0 +1,49 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'Cards', + componentName: 'cards', + tests: [ + { + description: 'permutations at 2200', + path: 'cards/permutations', + screenshotType: 'permutations', + configuration: { width: 2200 }, + }, + { + description: 'permutations at 1920', + path: 'cards/permutations', + screenshotType: 'permutations', + configuration: { width: 1920 }, + }, + { + description: 'permutations at 1400', + path: 'cards/permutations', + screenshotType: 'permutations', + configuration: { width: 1400 }, + }, + { + description: 'permutations at 1200', + path: 'cards/permutations', + screenshotType: 'permutations', + configuration: { width: 1200 }, + }, + { + description: 'permutations at 992', + path: 'cards/permutations', + screenshotType: 'permutations', + configuration: { width: 992 }, + }, + { + description: 'permutations at 768', + path: 'cards/permutations', + screenshotType: 'permutations', + configuration: { width: 768 }, + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/checkbox.ts b/test/definitions/visual/checkbox.ts new file mode 100644 index 0000000000..9f87723cf8 --- /dev/null +++ b/test/definitions/visual/checkbox.ts @@ -0,0 +1,37 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'Checkbox', + componentName: 'checkbox', + tests: [ + { + description: 'Permutations', + path: 'checkbox/permutations', + screenshotType: 'permutations', + }, + { + description: 'Checkbox is focused', + path: 'checkbox/focus-test', + screenshotType: 'screenshotArea', + setup: async ({ page }) => { + await page.click('#focus-target'); + await page.focusNextElement(); + }, + }, + { + description: 'Checkbox has label with a correct width', + path: 'checkbox/labels-highlight', + screenshotType: 'screenshotArea', + }, + { + description: 'Style custom page', + path: 'checkbox/style-custom', + screenshotType: 'screenshotArea', + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/code-editor.ts b/test/definitions/visual/code-editor.ts new file mode 100644 index 0000000000..0494b68bd8 --- /dev/null +++ b/test/definitions/visual/code-editor.ts @@ -0,0 +1,69 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const ACE_SELECTOR = '.ace_editor.ace-dawn, .ace_editor.ace-tomorrow-night-bright'; +const timeout = 20_000; + +const suite: TestSuite = { + description: 'Code editor', + componentName: 'code-editor', + tests: [ + { + description: 'simple', + path: 'code-editor/simple', + screenshotType: 'screenshotArea', + setup: async ({ page }) => { + await page.waitForVisible(ACE_SELECTOR, true, timeout); + }, + }, + { + description: 'error', + path: 'code-editor/error', + screenshotType: 'screenshotArea', + }, + { + description: 'loading', + path: 'code-editor/loading', + screenshotType: 'screenshotArea', + }, + { + description: 'theme resolution', + path: 'code-editor/themes', + screenshotType: 'screenshotArea', + setup: async ({ page }) => { + await page.waitForVisible(ACE_SELECTOR, true, timeout); + }, + }, + { + description: 'permutations', + path: 'code-editor/permutations', + screenshotType: 'permutations', + setup: async ({ page }) => { + await page.waitForVisible(ACE_SELECTOR + ' .ace_error'); + await page.waitForVisible('.ace_gutter-cell.ace_gutter-active-line.ace_error', true, timeout); + }, + }, + { + description: 'listens to mode change', + path: 'code-editor/simple', + screenshotType: 'screenshotArea', + setup: async ({ page }) => { + await page.waitForVisible(ACE_SELECTOR, true, timeout); + await page.click('#mode-toggle'); + }, + }, + { + description: 'compare simple on small screen', + path: 'code-editor/simple', + screenshotType: 'screenshotArea', + configuration: { width: 360 }, + setup: async ({ page }) => { + await page.waitForVisible(ACE_SELECTOR, true, timeout); + }, + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/collection-preferences.ts b/test/definitions/visual/collection-preferences.ts new file mode 100644 index 0000000000..a12ad8b545 --- /dev/null +++ b/test/definitions/visual/collection-preferences.ts @@ -0,0 +1,82 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'CollectionPreferences', + componentName: 'collection-preferences', + tests: [ + { + description: 'complete at 600x1100', + path: 'collection-preferences/simple', + screenshotType: 'viewport', + configuration: { width: 600, height: 1100 }, + setup: async ({ page }) => { + await page.click('.cp-1 button'); + }, + }, + { + description: 'visible content only at 600x1100', + path: 'collection-preferences/simple', + screenshotType: 'viewport', + setup: async ({ page }) => { + await page.click('.cp-4 button'); + }, + }, + { + description: 'complete at 1280x700', + path: 'collection-preferences/simple', + screenshotType: 'viewport', + configuration: { width: 1280, height: 700 }, + setup: async ({ page }) => { + await page.click('.cp-1 button'); + }, + }, + { + description: 'visible content only at 1280x700', + path: 'collection-preferences/simple', + screenshotType: 'viewport', + setup: async ({ page }) => { + await page.click('.cp-4 button'); + }, + }, + { + description: 'custom', + path: 'collection-preferences/simple', + screenshotType: 'viewport', + setup: async ({ page }) => { + await page.click('.cp-2 button'); + }, + }, + { + description: 'Content reordering', + componentName: 'collection-preferences', + tests: [ + { + description: 'drag handle focused', + path: 'collection-preferences/reorder-content', + screenshotType: 'viewport', + configuration: { width: 900, height: 650 }, + setup: async ({ page }) => { + await page.click('.cp-1 button'); + await page.keys(Array(5).fill('Tab')); + }, + }, + { + description: 'reordering active', + path: 'collection-preferences/reorder-content', + screenshotType: 'viewport', + configuration: { width: 900, height: 650 }, + setup: async ({ page }) => { + await page.click('.cp-1 button'); + await page.keys(Array(5).fill('Tab')); + await page.keys('Space'); + }, + }, + ], + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/column-layout.ts b/test/definitions/visual/column-layout.ts new file mode 100644 index 0000000000..a889050b9b --- /dev/null +++ b/test/definitions/visual/column-layout.ts @@ -0,0 +1,61 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'ColumnLayout', + componentName: 'column-layout', + tests: [ + { + description: 'column-layout at "default"', + path: 'column-layout/simple', + screenshotType: 'screenshotArea', + configuration: { width: 400 }, + }, + { + description: 'permutations at "default"', + path: 'column-layout/permutations', + screenshotType: 'permutations', + configuration: { width: 400 }, + }, + { + description: 'column-layout at "xxs"', + path: 'column-layout/simple', + screenshotType: 'screenshotArea', + configuration: { width: 500 }, + }, + { + description: 'permutations at "xxs"', + path: 'column-layout/permutations', + screenshotType: 'permutations', + configuration: { width: 500 }, + }, + { + description: 'column-layout at "xs"', + path: 'column-layout/simple', + screenshotType: 'screenshotArea', + configuration: { width: 800 }, + }, + { + description: 'permutations at "xs"', + path: 'column-layout/permutations', + screenshotType: 'permutations', + configuration: { width: 800 }, + }, + { + description: 'column-layout at "m"', + path: 'column-layout/simple', + screenshotType: 'screenshotArea', + configuration: { width: 1200 }, + }, + { + description: 'permutations at "m"', + path: 'column-layout/permutations', + screenshotType: 'permutations', + configuration: { width: 1200 }, + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/container-sticky.ts b/test/definitions/visual/container-sticky.ts new file mode 100644 index 0000000000..a322883a50 --- /dev/null +++ b/test/definitions/visual/container-sticky.ts @@ -0,0 +1,125 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'Container sticky permutations', + componentName: 'container', + tests: [ + { + description: 'simple - at 1400px', + path: 'container/sticky-permutations', + screenshotType: 'viewport', + configuration: { width: 1400 }, + setup: async ({ page }) => { + await page.windowScrollTo({ top: 200 }); + }, + }, + { + description: 'with notifications - at 1400px', + path: 'container/sticky-permutations', + screenshotType: 'viewport', + configuration: { width: 1400 }, + queryParams: { hasNotifications: 'true' }, + setup: async ({ page }) => { + await page.windowScrollTo({ top: 200 }); + }, + }, + { + description: 'with breadcrumbs - at 1400px', + path: 'container/sticky-permutations', + screenshotType: 'viewport', + configuration: { width: 1400 }, + queryParams: { hasBreadcrumbs: 'true' }, + setup: async ({ page }) => { + await page.windowScrollTo({ top: 200 }); + }, + }, + { + description: 'with an alert - at 1400px', + path: 'container/sticky-permutations', + screenshotType: 'viewport', + configuration: { width: 1400 }, + queryParams: { hasNotifications: 'true', hasAlert: 'true' }, + setup: async ({ page }) => { + await page.windowScrollTo({ top: 200 }); + }, + }, + { + description: 'with an alert - at 1400px without scroll', + path: 'container/sticky-permutations', + screenshotType: 'viewport', + configuration: { width: 1400 }, + queryParams: { hasNotifications: 'true', hasAlert: 'true' }, + }, + { + description: 'with high-contrast header - at 1400px', + path: 'container/sticky-permutations', + screenshotType: 'viewport', + configuration: { width: 1400 }, + queryParams: { hasNotifications: 'true', highContrast: 'true' }, + setup: async ({ page }) => { + await page.windowScrollTo({ top: 200 }); + }, + }, + { + description: 'simple - at 600px', + path: 'container/sticky-permutations', + screenshotType: 'viewport', + configuration: { width: 600 }, + setup: async ({ page }) => { + await page.windowScrollTo({ top: 200 }); + }, + }, + { + description: 'with notifications - at 600px', + path: 'container/sticky-permutations', + screenshotType: 'viewport', + configuration: { width: 600 }, + queryParams: { hasNotifications: 'true' }, + setup: async ({ page }) => { + await page.windowScrollTo({ top: 200 }); + }, + }, + { + description: 'with breadcrumbs - at 600px', + path: 'container/sticky-permutations', + screenshotType: 'viewport', + configuration: { width: 600 }, + queryParams: { hasBreadcrumbs: 'true' }, + setup: async ({ page }) => { + await page.windowScrollTo({ top: 200 }); + }, + }, + { + description: 'with an alert - at 600px', + path: 'container/sticky-permutations', + screenshotType: 'viewport', + configuration: { width: 600 }, + queryParams: { hasNotifications: 'true', hasAlert: 'true' }, + setup: async ({ page }) => { + await page.windowScrollTo({ top: 200 }); + }, + }, + { + description: 'with an alert - at 600px without scroll', + path: 'container/sticky-permutations', + screenshotType: 'viewport', + configuration: { width: 600 }, + queryParams: { hasNotifications: 'true', hasAlert: 'true' }, + }, + { + description: 'with high-contrast header - at 600px', + path: 'container/sticky-permutations', + screenshotType: 'viewport', + configuration: { width: 600 }, + queryParams: { hasNotifications: 'true', highContrast: 'true' }, + setup: async ({ page }) => { + await page.windowScrollTo({ top: 200 }); + }, + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/container.ts b/test/definitions/visual/container.ts new file mode 100644 index 0000000000..a0ac94e8d0 --- /dev/null +++ b/test/definitions/visual/container.ts @@ -0,0 +1,87 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'Container and header', + componentName: 'container', + tests: [ + { + description: 'simple', + path: 'container/simple', + screenshotType: 'screenshotArea', + }, + { + description: 'fit height with footer', + path: 'container/fit-height', + screenshotType: 'screenshotArea', + }, + { + description: 'fit height without footer', + path: 'container/fit-height', + screenshotType: 'screenshotArea', + queryParams: { hideFooters: 'true' }, + }, + { + description: 'correctly displays container with side media', + path: 'container/media', + screenshotType: 'screenshotArea', + queryParams: { position: 'side', width: '33%', content: '16-9' }, + }, + { + description: 'correctly displays container with top media', + path: 'container/media', + screenshotType: 'screenshotArea', + queryParams: { position: 'top', height: '150px', content: '4-3' }, + }, + { + description: 'media with position: side permutations at 465', + path: 'container/media-side-permutations', + screenshotType: 'permutations', + configuration: { width: 465 }, + }, + { + description: 'media with position: side permutations at 688', + path: 'container/media-side-permutations', + screenshotType: 'permutations', + configuration: { width: 688 }, + }, + { + description: 'media with position: side permutations at 1120', + path: 'container/media-side-permutations', + screenshotType: 'permutations', + configuration: { width: 1120 }, + }, + { + description: 'media with position: top permutations at 465', + path: 'container/media-top-permutations', + screenshotType: 'permutations', + configuration: { width: 465 }, + }, + { + description: 'media with position: top permutations at 688', + path: 'container/media-top-permutations', + screenshotType: 'permutations', + configuration: { width: 688 }, + }, + { + description: 'media with position: top permutations at 1120', + path: 'container/media-top-permutations', + screenshotType: 'permutations', + configuration: { width: 1120 }, + }, + { + description: 'stacked', + path: 'container/stacked-components', + screenshotType: 'screenshotArea', + }, + { + description: 'style-custom', + path: 'container/style-custom', + screenshotType: 'screenshotArea', + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/content-layout-permutations.ts b/test/definitions/visual/content-layout-permutations.ts new file mode 100644 index 0000000000..4f58d1a70d --- /dev/null +++ b/test/definitions/visual/content-layout-permutations.ts @@ -0,0 +1,661 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'ContentLayout permutations', + componentName: 'content-layout', + tests: [ + // default headerVariant + { + description: 'default headerVariant, none headerBackgroundStyle, at 1400, simple', + path: 'content-layout/permutations', + screenshotType: 'screenshotArea', + configuration: { width: 1400 }, + queryParams: { + hasBreadcrumbs: 'false', + hasNotifications: 'false', + disableOverlap: 'false', + hasAppLayout: 'false', + hasAppLayoutWithOpenNavigation: 'false', + hasSecondaryHeader: 'false', + removeHeader: 'false', + hasContainer: 'true', + defaultPadding: 'true', + headerVariant: 'default', + headerBackgroundStyle: 'none', + }, + }, + { + description: 'default headerVariant, none headerBackgroundStyle, at 1400, with notifications and breadcrumbs', + path: 'content-layout/permutations', + screenshotType: 'screenshotArea', + configuration: { width: 1400 }, + queryParams: { + hasBreadcrumbs: 'true', + hasNotifications: 'true', + disableOverlap: 'false', + hasAppLayout: 'false', + hasAppLayoutWithOpenNavigation: 'false', + hasSecondaryHeader: 'false', + removeHeader: 'false', + hasContainer: 'true', + defaultPadding: 'true', + headerVariant: 'default', + headerBackgroundStyle: 'none', + }, + }, + { + description: 'default headerVariant, none headerBackgroundStyle, at 600, simple', + path: 'content-layout/permutations', + screenshotType: 'screenshotArea', + configuration: { width: 600 }, + queryParams: { + hasBreadcrumbs: 'false', + hasNotifications: 'false', + disableOverlap: 'false', + hasAppLayout: 'false', + hasAppLayoutWithOpenNavigation: 'false', + hasSecondaryHeader: 'false', + removeHeader: 'false', + hasContainer: 'true', + defaultPadding: 'true', + headerVariant: 'default', + headerBackgroundStyle: 'none', + }, + }, + { + description: 'default headerVariant, none headerBackgroundStyle, at 600, with notifications and breadcrumbs', + path: 'content-layout/permutations', + screenshotType: 'screenshotArea', + configuration: { width: 600 }, + queryParams: { + hasBreadcrumbs: 'true', + hasNotifications: 'true', + disableOverlap: 'false', + hasAppLayout: 'false', + hasAppLayoutWithOpenNavigation: 'false', + hasSecondaryHeader: 'false', + removeHeader: 'false', + hasContainer: 'true', + defaultPadding: 'true', + headerVariant: 'default', + headerBackgroundStyle: 'none', + }, + }, + { + description: 'default headerVariant, none headerBackgroundStyle, with maxContentWidth', + path: 'content-layout/permutations', + screenshotType: 'screenshotArea', + configuration: { width: 1400 }, + queryParams: { + hasBreadcrumbs: 'true', + hasNotifications: 'true', + disableOverlap: 'false', + hasAppLayout: 'false', + hasAppLayoutWithOpenNavigation: 'false', + hasSecondaryHeader: 'false', + removeHeader: 'false', + hasContainer: 'true', + defaultPadding: 'true', + headerVariant: 'default', + headerBackgroundStyle: 'none', + maxContentWidth: '1000', + }, + }, + // default headerVariant, gradient + { + description: 'default headerVariant, gradient headerBackgroundStyle, at 1400, simple', + path: 'content-layout/permutations', + screenshotType: 'screenshotArea', + configuration: { width: 1400 }, + queryParams: { + hasBreadcrumbs: 'false', + hasNotifications: 'false', + disableOverlap: 'false', + hasAppLayout: 'false', + hasAppLayoutWithOpenNavigation: 'false', + hasSecondaryHeader: 'false', + removeHeader: 'false', + hasContainer: 'true', + defaultPadding: 'true', + headerVariant: 'default', + headerBackgroundStyle: 'gradient', + }, + }, + { + description: 'default headerVariant, gradient headerBackgroundStyle, at 1400, with notifications and breadcrumbs', + path: 'content-layout/permutations', + screenshotType: 'screenshotArea', + configuration: { width: 1400 }, + queryParams: { + hasBreadcrumbs: 'true', + hasNotifications: 'true', + disableOverlap: 'false', + hasAppLayout: 'false', + hasAppLayoutWithOpenNavigation: 'false', + hasSecondaryHeader: 'false', + removeHeader: 'false', + hasContainer: 'true', + defaultPadding: 'true', + headerVariant: 'default', + headerBackgroundStyle: 'gradient', + }, + }, + { + description: 'default headerVariant, gradient headerBackgroundStyle, with maxContentWidth', + path: 'content-layout/permutations', + screenshotType: 'screenshotArea', + configuration: { width: 1400 }, + queryParams: { + hasBreadcrumbs: 'true', + hasNotifications: 'true', + disableOverlap: 'false', + hasAppLayout: 'false', + hasAppLayoutWithOpenNavigation: 'false', + hasSecondaryHeader: 'false', + removeHeader: 'false', + hasContainer: 'true', + defaultPadding: 'true', + headerVariant: 'default', + headerBackgroundStyle: 'gradient', + maxContentWidth: '1000', + }, + }, + // high-contrast headerVariant, none + { + description: 'high-contrast headerVariant, none headerBackgroundStyle, at 1400, simple', + path: 'content-layout/permutations', + screenshotType: 'screenshotArea', + configuration: { width: 1400 }, + queryParams: { + hasBreadcrumbs: 'false', + hasNotifications: 'false', + disableOverlap: 'false', + hasAppLayout: 'false', + hasAppLayoutWithOpenNavigation: 'false', + hasSecondaryHeader: 'false', + removeHeader: 'false', + hasContainer: 'true', + defaultPadding: 'true', + headerVariant: 'high-contrast', + headerBackgroundStyle: 'none', + }, + }, + { + description: + 'high-contrast headerVariant, none headerBackgroundStyle, at 1400, with notifications and breadcrumbs', + path: 'content-layout/permutations', + screenshotType: 'screenshotArea', + configuration: { width: 1400 }, + queryParams: { + hasBreadcrumbs: 'true', + hasNotifications: 'true', + disableOverlap: 'false', + hasAppLayout: 'false', + hasAppLayoutWithOpenNavigation: 'false', + hasSecondaryHeader: 'false', + removeHeader: 'false', + hasContainer: 'true', + defaultPadding: 'true', + headerVariant: 'high-contrast', + headerBackgroundStyle: 'none', + }, + }, + { + description: 'high-contrast headerVariant, none headerBackgroundStyle, with maxContentWidth', + path: 'content-layout/permutations', + screenshotType: 'screenshotArea', + configuration: { width: 1400 }, + queryParams: { + hasBreadcrumbs: 'true', + hasNotifications: 'true', + disableOverlap: 'false', + hasAppLayout: 'false', + hasAppLayoutWithOpenNavigation: 'false', + hasSecondaryHeader: 'false', + removeHeader: 'false', + hasContainer: 'true', + defaultPadding: 'true', + headerVariant: 'high-contrast', + headerBackgroundStyle: 'none', + maxContentWidth: '1000', + }, + }, + // high-contrast headerVariant, gradient + { + description: 'high-contrast headerVariant, gradient headerBackgroundStyle, at 1400, simple', + path: 'content-layout/permutations', + screenshotType: 'screenshotArea', + configuration: { width: 1400 }, + queryParams: { + hasBreadcrumbs: 'false', + hasNotifications: 'false', + disableOverlap: 'false', + hasAppLayout: 'false', + hasAppLayoutWithOpenNavigation: 'false', + hasSecondaryHeader: 'false', + removeHeader: 'false', + hasContainer: 'true', + defaultPadding: 'true', + headerVariant: 'high-contrast', + headerBackgroundStyle: 'gradient', + }, + }, + { + description: + 'high-contrast headerVariant, gradient headerBackgroundStyle, at 1400, with notifications and breadcrumbs', + path: 'content-layout/permutations', + screenshotType: 'screenshotArea', + configuration: { width: 1400 }, + queryParams: { + hasBreadcrumbs: 'true', + hasNotifications: 'true', + disableOverlap: 'false', + hasAppLayout: 'false', + hasAppLayoutWithOpenNavigation: 'false', + hasSecondaryHeader: 'false', + removeHeader: 'false', + hasContainer: 'true', + defaultPadding: 'true', + headerVariant: 'high-contrast', + headerBackgroundStyle: 'gradient', + }, + }, + { + description: 'high-contrast headerVariant, gradient headerBackgroundStyle, with maxContentWidth', + path: 'content-layout/permutations', + screenshotType: 'screenshotArea', + configuration: { width: 1400 }, + queryParams: { + hasBreadcrumbs: 'true', + hasNotifications: 'true', + disableOverlap: 'false', + hasAppLayout: 'false', + hasAppLayoutWithOpenNavigation: 'false', + hasSecondaryHeader: 'false', + removeHeader: 'false', + hasContainer: 'true', + defaultPadding: 'true', + headerVariant: 'high-contrast', + headerBackgroundStyle: 'gradient', + maxContentWidth: '1000', + }, + }, + // divider headerVariant + { + description: 'divider headerVariant, at 1400, simple', + path: 'content-layout/permutations', + screenshotType: 'screenshotArea', + configuration: { width: 1400 }, + queryParams: { + hasBreadcrumbs: 'false', + hasNotifications: 'false', + disableOverlap: 'false', + hasAppLayout: 'false', + hasAppLayoutWithOpenNavigation: 'false', + hasSecondaryHeader: 'false', + removeHeader: 'false', + hasContainer: 'true', + defaultPadding: 'true', + headerVariant: 'divider', + headerBackgroundStyle: 'none', + }, + }, + { + description: 'divider headerVariant, at 1400, with maxContentWidth', + path: 'content-layout/permutations', + screenshotType: 'screenshotArea', + configuration: { width: 1400 }, + queryParams: { + hasBreadcrumbs: 'true', + hasNotifications: 'true', + disableOverlap: 'true', + hasAppLayout: 'false', + hasAppLayoutWithOpenNavigation: 'false', + hasSecondaryHeader: 'false', + removeHeader: 'false', + hasContainer: 'false', + defaultPadding: 'true', + headerVariant: 'divider', + headerBackgroundStyle: 'none', + maxContentWidth: '1000', + }, + }, + { + description: 'divider headerVariant, at 600, simple', + path: 'content-layout/permutations', + screenshotType: 'screenshotArea', + configuration: { width: 600 }, + queryParams: { + hasBreadcrumbs: 'false', + hasNotifications: 'false', + disableOverlap: 'false', + hasAppLayout: 'false', + hasAppLayoutWithOpenNavigation: 'false', + hasSecondaryHeader: 'false', + removeHeader: 'false', + hasContainer: 'true', + defaultPadding: 'true', + headerVariant: 'divider', + headerBackgroundStyle: 'none', + }, + }, + { + description: 'divider headerVariant, at 600, with maxContentWidth', + path: 'content-layout/permutations', + screenshotType: 'screenshotArea', + configuration: { width: 600 }, + queryParams: { + hasBreadcrumbs: 'true', + hasNotifications: 'true', + disableOverlap: 'true', + hasAppLayout: 'false', + hasAppLayoutWithOpenNavigation: 'false', + hasSecondaryHeader: 'false', + removeHeader: 'false', + hasContainer: 'false', + defaultPadding: 'true', + headerVariant: 'divider', + headerBackgroundStyle: 'none', + maxContentWidth: '1000', + }, + }, + // with app layout + { + description: 'with app layout, divider headerVariant, at 1400, simple', + path: 'content-layout/permutations', + screenshotType: 'screenshotArea', + configuration: { width: 1400 }, + queryParams: { + hasBreadcrumbs: 'false', + hasNotifications: 'false', + disableOverlap: 'true', + hasAppLayout: 'true', + hasAppLayoutWithOpenNavigation: 'false', + hasSecondaryHeader: 'false', + removeHeader: 'false', + hasContainer: 'false', + defaultPadding: 'true', + headerVariant: 'divider', + headerBackgroundStyle: 'none', + }, + }, + { + description: 'with app layout, high-contrast gradient, at 1400, with maxContentWidth', + path: 'content-layout/permutations', + screenshotType: 'screenshotArea', + configuration: { width: 1400 }, + queryParams: { + hasBreadcrumbs: 'true', + hasNotifications: 'true', + disableOverlap: 'false', + hasAppLayout: 'true', + hasAppLayoutWithOpenNavigation: 'false', + hasSecondaryHeader: 'false', + removeHeader: 'false', + hasContainer: 'true', + defaultPadding: 'true', + headerVariant: 'high-contrast', + headerBackgroundStyle: 'gradient', + maxContentWidth: '800', + }, + }, + { + description: 'with open navigation, without maxContentWidth', + path: 'content-layout/permutations', + screenshotType: 'screenshotArea', + configuration: { width: 1400 }, + queryParams: { + hasBreadcrumbs: 'false', + hasNotifications: 'false', + disableOverlap: 'false', + hasAppLayout: 'true', + hasAppLayoutWithOpenNavigation: 'true', + hasSecondaryHeader: 'false', + removeHeader: 'false', + hasContainer: 'true', + defaultPadding: 'true', + headerVariant: 'high-contrast', + headerBackgroundStyle: 'none', + }, + }, + { + description: 'with open navigation, with maxContentWidth', + path: 'content-layout/permutations', + screenshotType: 'screenshotArea', + configuration: { width: 1400 }, + queryParams: { + hasBreadcrumbs: 'true', + hasNotifications: 'true', + disableOverlap: 'false', + hasAppLayout: 'true', + hasAppLayoutWithOpenNavigation: 'true', + hasSecondaryHeader: 'false', + removeHeader: 'false', + hasContainer: 'true', + defaultPadding: 'true', + headerVariant: 'divider', + headerBackgroundStyle: 'none', + maxContentWidth: '700', + }, + }, + // with secondary header + { + description: 'with secondary header, at 1400', + path: 'content-layout/permutations', + screenshotType: 'screenshotArea', + configuration: { width: 1400 }, + queryParams: { + hasBreadcrumbs: 'false', + hasNotifications: 'false', + disableOverlap: 'false', + hasAppLayout: 'false', + hasAppLayoutWithOpenNavigation: 'false', + hasSecondaryHeader: 'true', + removeHeader: 'false', + hasContainer: 'true', + defaultPadding: 'true', + headerVariant: 'high-contrast', + headerBackgroundStyle: 'none', + }, + }, + { + description: 'with secondary header, at 600', + path: 'content-layout/permutations', + screenshotType: 'screenshotArea', + configuration: { width: 600 }, + queryParams: { + hasBreadcrumbs: 'false', + hasNotifications: 'false', + disableOverlap: 'false', + hasAppLayout: 'false', + hasAppLayoutWithOpenNavigation: 'false', + hasSecondaryHeader: 'true', + removeHeader: 'false', + hasContainer: 'true', + defaultPadding: 'true', + headerVariant: 'high-contrast', + headerBackgroundStyle: 'none', + }, + }, + { + description: 'with secondary header, with maxContentWidth', + path: 'content-layout/permutations', + screenshotType: 'screenshotArea', + configuration: { width: 1400 }, + queryParams: { + hasBreadcrumbs: 'false', + hasNotifications: 'false', + disableOverlap: 'false', + hasAppLayout: 'false', + hasAppLayoutWithOpenNavigation: 'false', + hasSecondaryHeader: 'true', + removeHeader: 'false', + hasContainer: 'true', + defaultPadding: 'true', + headerVariant: 'high-contrast', + headerBackgroundStyle: 'none', + maxContentWidth: '900', + }, + }, + // without header + { + description: 'without header, at 1400, defaultPadding=true, default headerVariant', + path: 'content-layout/permutations', + screenshotType: 'screenshotArea', + configuration: { width: 1400 }, + queryParams: { + hasBreadcrumbs: 'false', + hasNotifications: 'false', + disableOverlap: 'false', + hasAppLayout: 'false', + hasAppLayoutWithOpenNavigation: 'false', + hasSecondaryHeader: 'false', + removeHeader: 'true', + hasContainer: 'true', + defaultPadding: 'true', + headerVariant: 'default', + headerBackgroundStyle: 'none', + }, + }, + { + description: 'without header, at 1400, defaultPadding=true, high-contrast headerVariant', + path: 'content-layout/permutations', + screenshotType: 'screenshotArea', + configuration: { width: 1400 }, + queryParams: { + hasBreadcrumbs: 'false', + hasNotifications: 'false', + disableOverlap: 'false', + hasAppLayout: 'false', + hasAppLayoutWithOpenNavigation: 'false', + hasSecondaryHeader: 'false', + removeHeader: 'true', + hasContainer: 'true', + defaultPadding: 'true', + headerVariant: 'high-contrast', + headerBackgroundStyle: 'none', + }, + }, + { + description: 'without header, at 1400, defaultPadding=true, divider headerVariant', + path: 'content-layout/permutations', + screenshotType: 'screenshotArea', + configuration: { width: 1400 }, + queryParams: { + hasBreadcrumbs: 'false', + hasNotifications: 'false', + disableOverlap: 'false', + hasAppLayout: 'false', + hasAppLayoutWithOpenNavigation: 'false', + hasSecondaryHeader: 'false', + removeHeader: 'true', + hasContainer: 'true', + defaultPadding: 'true', + headerVariant: 'divider', + headerBackgroundStyle: 'none', + }, + }, + { + description: 'without header, at 1400, defaultPadding=false, default headerVariant', + path: 'content-layout/permutations', + screenshotType: 'screenshotArea', + configuration: { width: 1400 }, + queryParams: { + hasBreadcrumbs: 'false', + hasNotifications: 'false', + disableOverlap: 'false', + hasAppLayout: 'false', + hasAppLayoutWithOpenNavigation: 'false', + hasSecondaryHeader: 'false', + removeHeader: 'true', + hasContainer: 'true', + defaultPadding: 'false', + headerVariant: 'default', + headerBackgroundStyle: 'none', + }, + }, + // without default padding + { + description: 'without default padding, at 1400', + path: 'content-layout/permutations', + screenshotType: 'screenshotArea', + configuration: { width: 1400 }, + queryParams: { + hasBreadcrumbs: 'false', + hasNotifications: 'false', + disableOverlap: 'false', + hasAppLayout: 'false', + hasAppLayoutWithOpenNavigation: 'false', + hasSecondaryHeader: 'false', + removeHeader: 'false', + hasContainer: 'true', + defaultPadding: 'false', + headerVariant: 'default', + headerBackgroundStyle: 'none', + }, + }, + { + description: 'without default padding, at 600', + path: 'content-layout/permutations', + screenshotType: 'screenshotArea', + configuration: { width: 600 }, + queryParams: { + hasBreadcrumbs: 'false', + hasNotifications: 'false', + disableOverlap: 'false', + hasAppLayout: 'false', + hasAppLayoutWithOpenNavigation: 'false', + hasSecondaryHeader: 'false', + removeHeader: 'false', + hasContainer: 'true', + defaultPadding: 'false', + headerVariant: 'default', + headerBackgroundStyle: 'none', + }, + }, + // with disabled overlap + { + description: 'with disabled overlap, at 1400', + path: 'content-layout/permutations', + screenshotType: 'screenshotArea', + configuration: { width: 1400 }, + queryParams: { + hasBreadcrumbs: 'false', + hasNotifications: 'false', + disableOverlap: 'true', + hasAppLayout: 'false', + hasAppLayoutWithOpenNavigation: 'false', + hasSecondaryHeader: 'false', + removeHeader: 'false', + hasContainer: 'false', + defaultPadding: 'true', + headerVariant: 'high-contrast', + headerBackgroundStyle: 'none', + }, + }, + { + description: 'with disabled overlap, at 600', + path: 'content-layout/permutations', + screenshotType: 'screenshotArea', + configuration: { width: 600 }, + queryParams: { + hasBreadcrumbs: 'false', + hasNotifications: 'false', + disableOverlap: 'true', + hasAppLayout: 'false', + hasAppLayoutWithOpenNavigation: 'false', + hasSecondaryHeader: 'false', + removeHeader: 'false', + hasContainer: 'false', + defaultPadding: 'true', + headerVariant: 'high-contrast', + headerBackgroundStyle: 'none', + }, + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/content-layout.ts b/test/definitions/visual/content-layout.ts new file mode 100644 index 0000000000..ea88b5de4c --- /dev/null +++ b/test/definitions/visual/content-layout.ts @@ -0,0 +1,98 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'ContentLayout', + componentName: 'content-layout', + tests: [ + { + description: 'fill content area', + path: 'content-layout/fill-content-area', + screenshotType: 'screenshotArea', + }, + { + description: 'standalone', + path: 'content-layout/standalone', + screenshotType: 'screenshotArea', + }, + { + description: 'with absolute components', + path: 'content-layout/with-absolute-components', + screenshotType: 'screenshotArea', + }, + { + description: 'form with form header', + path: 'content-layout/with-header-toggles', + screenshotType: 'screenshotArea', + }, + { + description: 'form with content layout header', + path: 'content-layout/with-header-toggles', + screenshotType: 'screenshotArea', + setup: async ({ page }) => { + await page.click('[data-testid="toggle-form-header"] input'); + await page.click('[data-testid="toggle-content-layout"] input'); + }, + }, + { + description: 'without header - at 1400 without breadcrumbs, without notifications, with overlap', + path: 'content-layout/without-header', + screenshotType: 'screenshotArea', + configuration: { width: 1400 }, + queryParams: { hasBreadcrumbs: 'false', hasNotifications: 'false', disableOverlap: 'false' }, + }, + { + description: 'without header - at 1400 with breadcrumbs, without notifications, with overlap', + path: 'content-layout/without-header', + screenshotType: 'screenshotArea', + configuration: { width: 1400 }, + queryParams: { hasBreadcrumbs: 'true', hasNotifications: 'false', disableOverlap: 'false' }, + }, + { + description: 'without header - at 1400 without breadcrumbs, with notifications, with overlap', + path: 'content-layout/without-header', + screenshotType: 'screenshotArea', + configuration: { width: 1400 }, + queryParams: { hasBreadcrumbs: 'false', hasNotifications: 'true', disableOverlap: 'false' }, + }, + { + description: 'without header - at 1400 with breadcrumbs, with notifications, with overlap', + path: 'content-layout/without-header', + screenshotType: 'screenshotArea', + configuration: { width: 1400 }, + queryParams: { hasBreadcrumbs: 'true', hasNotifications: 'true', disableOverlap: 'false' }, + }, + { + description: 'without header - at 1400 without breadcrumbs, without notifications, without overlap', + path: 'content-layout/without-header', + screenshotType: 'screenshotArea', + configuration: { width: 1400 }, + queryParams: { hasBreadcrumbs: 'false', hasNotifications: 'false', disableOverlap: 'true' }, + }, + { + description: 'without header - at 1400 with breadcrumbs, with notifications, without overlap', + path: 'content-layout/without-header', + screenshotType: 'screenshotArea', + configuration: { width: 1400 }, + queryParams: { hasBreadcrumbs: 'true', hasNotifications: 'true', disableOverlap: 'true' }, + }, + { + description: 'without header - at 600 without breadcrumbs, without notifications, with overlap', + path: 'content-layout/without-header', + screenshotType: 'screenshotArea', + configuration: { width: 600 }, + queryParams: { hasBreadcrumbs: 'false', hasNotifications: 'false', disableOverlap: 'false' }, + }, + { + description: 'without header - at 600 with breadcrumbs, with notifications, with overlap', + path: 'content-layout/without-header', + screenshotType: 'screenshotArea', + configuration: { width: 600 }, + queryParams: { hasBreadcrumbs: 'true', hasNotifications: 'true', disableOverlap: 'false' }, + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/copy-to-clipboard.ts b/test/definitions/visual/copy-to-clipboard.ts new file mode 100644 index 0000000000..250ecbb6f4 --- /dev/null +++ b/test/definitions/visual/copy-to-clipboard.ts @@ -0,0 +1,28 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'CopyToClipboard', + componentName: 'copy-to-clipboard', + tests: [ + { + description: 'Variants', + path: 'copy-to-clipboard/simple', + screenshotType: 'screenshotArea', + }, + { + description: 'copy-to-clipboard below bottom split panel is not visible', + path: 'copy-to-clipboard/scenario-split-panel', + screenshotType: 'screenshotArea', + configuration: { width: 1280, height: 900 }, + setup: async ({ page, browser }) => { + await page.click('[aria-label="Copy dummy text"]'); + browser.$('[data-testid="scroll-me"]').scrollIntoView(); + }, + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/date-input.ts b/test/definitions/visual/date-input.ts new file mode 100644 index 0000000000..431b274b22 --- /dev/null +++ b/test/definitions/visual/date-input.ts @@ -0,0 +1,23 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'Date input', + componentName: 'date-input', + tests: [ + { + description: 'Permutations: states', + path: 'date-input/permutations-states', + screenshotType: 'permutations', + }, + { + description: 'Permutations: formats', + path: 'date-input/permutations-formats', + screenshotType: 'permutations', + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/date-picker.ts b/test/definitions/visual/date-picker.ts new file mode 100644 index 0000000000..c694cc816b --- /dev/null +++ b/test/definitions/visual/date-picker.ts @@ -0,0 +1,61 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'Date picker', + componentName: 'date-picker', + tests: [ + { + description: 'Permutations: states', + path: 'date-picker/permutations', + screenshotType: 'permutations', + setup: async ({ page }) => { + await page.click('[data-testid="date-picker-expanded-example"] button'); + }, + }, + { + description: 'Permutations: formats', + path: 'date-picker/permutations-formats', + screenshotType: 'permutations', + }, + { + description: 'Month picker', + componentName: 'date-picker', + tests: [ + { + description: 'focus ring on selected month', + path: 'date-picker/month-picker', + screenshotType: 'screenshotArea', + setup: async ({ page, wrapper }) => { + await page.click(wrapper.findDatePicker().findOpenCalendarButton().toSelector()); + await page.keys(['Tab', 'Tab', 'Tab']); + }, + }, + { + description: 'focus ring on current month', + path: 'date-picker/month-picker', + screenshotType: 'screenshotArea', + setup: async ({ page, wrapper }) => { + await page.click(wrapper.findDatePicker().findOpenCalendarButton().toSelector()); + await page.keys(['Tab', 'Tab', 'Tab']); + await page.keys(['ArrowRight']); + }, + }, + { + description: 'focus ring on non selected, non current month', + path: 'date-picker/month-picker', + screenshotType: 'screenshotArea', + setup: async ({ page, wrapper }) => { + await page.click(wrapper.findDatePicker().findOpenCalendarButton().toSelector()); + await page.keys(['Tab', 'Tab', 'Tab']); + await page.keys(['ArrowRight', 'ArrowRight']); + }, + }, + ], + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/date-range-picker.ts b/test/definitions/visual/date-range-picker.ts new file mode 100644 index 0000000000..eb5ce32e32 --- /dev/null +++ b/test/definitions/visual/date-range-picker.ts @@ -0,0 +1,121 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'Date Range Picker', + componentName: 'date-range-picker', + tests: [ + { + description: 'Absolute range at 450px', + path: 'date-range-picker/with-value', + screenshotType: 'screenshotArea', + configuration: { width: 450, height: 950 }, + setup: async ({ page }) => { + await page.click('#focusable-before'); + await page.focusNextElement(); + await page.keys(['Enter']); + await page.click('[data-date="2018-01-09"]'); + await page.click('[data-date="2018-01-27"]'); + }, + }, + { + description: 'Absolute range at 1200px', + path: 'date-range-picker/with-value', + screenshotType: 'screenshotArea', + configuration: { width: 1200, height: 950 }, + setup: async ({ page }) => { + await page.click('#focusable-before'); + await page.focusNextElement(); + await page.keys(['Enter']); + await page.click('[data-date="2018-01-09"]'); + await page.click('[data-date="2018-02-24"]'); + }, + }, + { + description: 'Absolute range input permutations for day granularity', + path: 'date-range-picker/absolute-format-day-picker.permutations', + screenshotType: 'screenshotArea', + }, + { + description: 'Absolute range input permutations for month granularity', + path: 'date-range-picker/absolute-format-month-picker.permutations', + screenshotType: 'permutations', + }, + { + description: 'Relative range at 450px', + path: 'date-range-picker/with-value', + screenshotType: 'screenshotArea', + configuration: { width: 450, height: 950 }, + setup: async ({ page }) => { + await page.click('#focusable-before'); + await page.focusNextElement(); + await page.keys(['Enter']); + await page.focusNextElement(); + await page.keys(['Space']); + await page.keys(['ArrowUp']); + await page.keys(['Enter']); + await page.focusNextElement(); + await page.keys(['ArrowDown', 'ArrowDown', 'ArrowDown', 'ArrowDown']); + }, + }, + { + description: 'Relative range at 1200px', + path: 'date-range-picker/with-value', + screenshotType: 'screenshotArea', + configuration: { width: 1200, height: 950 }, + setup: async ({ page }) => { + await page.click('#focusable-before'); + await page.focusNextElement(); + await page.keys(['Enter']); + await page.focusNextElement(); + await page.keys(['ArrowLeft']); + await page.keys(['Enter']); + await page.focusNextElement(); + await page.keys(['ArrowDown', 'ArrowDown', 'ArrowDown', 'ArrowDown']); + }, + }, + { + description: 'Calendar permutations for day granularity', + path: 'date-range-picker/month-calendar-permutations', + screenshotType: 'permutations', + }, + { + description: 'Calendar permutations for month granularity', + path: 'date-range-picker/year-calendar-permutations', + screenshotType: 'permutations', + }, + { + description: 'selects text when double-clicking calendar header', + path: 'date-range-picker/with-value', + screenshotType: 'screenshotArea', + setup: async ({ page, wrapper, browser }) => { + await page.click('#focusable-before'); + await page.focusNextElement(); + await page.keys(['Enter']); + const firstCalendarHeaderSelector = wrapper + .findDateRangePicker() + .findDropdown() + .findHeader() + .find('h2 span') + .toSelector(); + browser.$(firstCalendarHeaderSelector).doubleClick(); + }, + }, + { + description: 'does not select text when double-clicking next button', + path: 'date-range-picker/with-value', + screenshotType: 'screenshotArea', + setup: async ({ page, wrapper, browser }) => { + await page.click('#focusable-before'); + await page.focusNextElement(); + await page.keys(['Enter']); + const nextButtonSelector = wrapper.findDateRangePicker().findDropdown().findNextMonthButton().toSelector(); + browser.$(nextButtonSelector).doubleClick(); + }, + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/divider.ts b/test/definitions/visual/divider.ts new file mode 100644 index 0000000000..8dbed83984 --- /dev/null +++ b/test/definitions/visual/divider.ts @@ -0,0 +1,18 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'Divider', + componentName: 'divider', + tests: [ + { + description: 'permutations', + path: 'divider/permutations', + screenshotType: 'permutations', + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/drawer.ts b/test/definitions/visual/drawer.ts new file mode 100644 index 0000000000..e81a979769 --- /dev/null +++ b/test/definitions/visual/drawer.ts @@ -0,0 +1,105 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'Drawer', + componentName: 'drawer', + tests: [ + { + description: 'permutations', + path: 'drawer/permutations', + screenshotType: 'permutations', + }, + { + description: 'short content, with footer, short footer', + path: 'app-layout/drawer-with-footer', + screenshotType: 'viewport', + queryParams: { longContent: 'false', longFooter: 'false', hasFooter: 'true' }, + }, + { + description: 'short content, with footer, long footer', + path: 'app-layout/drawer-with-footer', + screenshotType: 'viewport', + queryParams: { longContent: 'false', longFooter: 'true', hasFooter: 'true' }, + }, + { + description: 'long content, with footer, short footer', + path: 'app-layout/drawer-with-footer', + screenshotType: 'viewport', + queryParams: { longContent: 'true', longFooter: 'false', hasFooter: 'true' }, + }, + { + description: 'long content, with footer, long footer', + path: 'app-layout/drawer-with-footer', + screenshotType: 'viewport', + queryParams: { longContent: 'true', longFooter: 'true', hasFooter: 'true' }, + }, + { + description: 'Drawer with small view height', + path: 'app-layout/drawer-with-footer', + screenshotType: 'viewport', + configuration: { width: 1280, height: 268 }, + queryParams: { longContent: 'true', hasFooter: 'true', longFooter: 'true' }, + }, + { + description: 'Drawer footer with small view height', + path: 'app-layout/drawer-with-footer', + screenshotType: 'viewport', + configuration: { width: 1280, height: 268 }, + queryParams: { longContent: 'true', hasFooter: 'true' }, + setup: ({ browser, wrapper }) => { + browser.$(wrapper.findDrawer().findFooter().toSelector()).scrollIntoView(); + }, + }, + { + description: 'Drawer with absolute position', + path: 'drawer/drawer-position-absolute', + screenshotType: 'viewport', + configuration: { width: 1200, height: 1000 }, + }, + { + description: 'Drawer with absolute position and backdrops', + path: 'drawer/drawer-position-absolute', + screenshotType: 'viewport', + configuration: { width: 1200, height: 1000 }, + queryParams: { backdrops: 'start,end' }, + }, + { + description: 'Drawer with sticky position', + path: 'drawer/drawer-position-sticky', + screenshotType: 'viewport', + configuration: { width: 1200, height: 1000 }, + }, + { + description: 'Drawer with sticky position and offsets', + path: 'drawer/drawer-position-sticky', + screenshotType: 'viewport', + configuration: { width: 1200, height: 1000 }, + queryParams: { offsets: 'true' }, + }, + { + description: 'Drawer with sticky position and sticky offsets', + path: 'drawer/drawer-position-sticky', + screenshotType: 'viewport', + configuration: { width: 1200, height: 1000 }, + queryParams: { stickyOffsets: 'true' }, + }, + { + description: 'Drawer with fixed position', + path: 'drawer/drawer-position-fixed', + screenshotType: 'viewport', + configuration: { width: 1200, height: 1000 }, + }, + { + description: 'Drawer with fixed position, offsets and backdrop', + path: 'drawer/drawer-position-fixed', + screenshotType: 'viewport', + configuration: { width: 1200, height: 1000 }, + queryParams: { offsets: 'true', backdrop: 'true' }, + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/dropdown.ts b/test/definitions/visual/dropdown.ts new file mode 100644 index 0000000000..4bbb716e5d --- /dev/null +++ b/test/definitions/visual/dropdown.ts @@ -0,0 +1,83 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'Dropdown', + componentName: 'dropdown', + tests: [ + { + description: 'In fixed container', + path: 'dropdown/fixed-container', + screenshotType: 'viewport', + setup: async ({ page }) => { + const { height: windowHeight } = await page.getViewportSize(); + await page.windowScrollTo({ top: windowHeight }); + await page.click('button=Open dropdown'); + }, + }, + { + description: 'positions select inside modal, expandToViewport=false', + path: 'dropdown/expandable', + screenshotType: 'viewport', + queryParams: { componentType: 'Select', expandToViewport: 'false' }, + setup: async ({ page }) => { + await page.click('#show-modal'); + await page.click('#in-modal'); + }, + }, + { + description: 'positions select inside modal, expandToViewport=true', + path: 'dropdown/expandable', + screenshotType: 'viewport', + queryParams: { componentType: 'Select', expandToViewport: 'true' }, + setup: async ({ page }) => { + await page.click('#show-modal'); + await page.click('#in-modal'); + }, + }, + { + description: 'positions select inside popover, expandToViewport=false', + path: 'dropdown/expandable', + screenshotType: 'viewport', + queryParams: { componentType: 'Select', expandToViewport: 'false' }, + setup: async ({ page }) => { + await page.click('#show-popover'); + await page.click('#in-popover'); + await page.click('[data-test-index="5"]'); + }, + }, + { + description: 'positions select inside popover, expandToViewport=true', + path: 'dropdown/expandable', + screenshotType: 'viewport', + queryParams: { componentType: 'Select', expandToViewport: 'true' }, + setup: async ({ page }) => { + await page.click('#show-popover'); + await page.click('#in-popover'); + await page.click('[data-test-index="5"]'); + }, + }, + { + description: 'select has bottom borders when opened upwards, expandToViewport=false', + path: 'dropdown/expandable', + screenshotType: 'viewport', + queryParams: { componentType: 'Select', expandToViewport: 'false' }, + setup: async ({ page }) => { + await page.click('#bottom-left'); + }, + }, + { + description: 'select has bottom borders when opened upwards, expandToViewport=true', + path: 'dropdown/expandable', + screenshotType: 'viewport', + queryParams: { componentType: 'Select', expandToViewport: 'true' }, + setup: async ({ page }) => { + await page.click('#bottom-left'); + }, + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/expandable-section.ts b/test/definitions/visual/expandable-section.ts new file mode 100644 index 0000000000..9564685028 --- /dev/null +++ b/test/definitions/visual/expandable-section.ts @@ -0,0 +1,124 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'Expandable section', + componentName: 'expandable-section', + tests: [ + { + description: 'permutations', + path: 'expandable-section/permutations', + screenshotType: 'permutations', + }, + { + description: 'container variant', + path: 'expandable-section/container-variant.permutations', + screenshotType: 'permutations', + }, + { + description: 'focus - container variant with only heading', + path: 'expandable-section/focus', + screenshotType: 'screenshotArea', + queryParams: { headerText: 'Header text', variant: 'container' }, + setup: async ({ page }) => { + await page.click('#focus-target'); + await page.focusNextElement(); + }, + }, + { + description: 'focus - default variant with only heading', + path: 'expandable-section/focus', + screenshotType: 'screenshotArea', + queryParams: { headerText: 'Header text', variant: 'default' }, + setup: async ({ page }) => { + await page.click('#focus-target'); + await page.focusNextElement(); + }, + }, + { + description: 'focus - footer variant with only heading', + path: 'expandable-section/focus', + screenshotType: 'screenshotArea', + queryParams: { headerText: 'Header text', variant: 'footer' }, + setup: async ({ page }) => { + await page.click('#focus-target'); + await page.focusNextElement(); + }, + }, + { + description: 'focus - navigation variant with only heading', + path: 'expandable-section/focus', + screenshotType: 'screenshotArea', + queryParams: { headerText: 'Header text', variant: 'navigation' }, + setup: async ({ page }) => { + await page.click('#focus-target'); + await page.focusNextElement(); + }, + }, + { + description: 'focus - container variant with heading and description', + path: 'expandable-section/focus', + screenshotType: 'screenshotArea', + queryParams: { headerText: 'Header text', headerDescription: 'Header description', variant: 'container' }, + setup: async ({ page }) => { + await page.click('#focus-target'); + await page.focusNextElement(); + }, + }, + { + description: 'focus - default variant with heading and description', + path: 'expandable-section/focus', + screenshotType: 'screenshotArea', + queryParams: { headerText: 'Header text', headerDescription: 'Header description', variant: 'default' }, + setup: async ({ page }) => { + await page.click('#focus-target'); + await page.focusNextElement(); + }, + }, + { + description: 'focus - footer variant with heading and description', + path: 'expandable-section/focus', + screenshotType: 'screenshotArea', + queryParams: { headerText: 'Header text', headerDescription: 'Header description', variant: 'footer' }, + setup: async ({ page }) => { + await page.click('#focus-target'); + await page.focusNextElement(); + }, + }, + { + description: 'focus - container variant with interactive elements', + path: 'expandable-section/focus', + screenshotType: 'screenshotArea', + queryParams: { headerText: 'Header text', hasHeaderInfo: 'true', hasHeaderActions: 'true', variant: 'container' }, + setup: async ({ page }) => { + await page.click('#focus-target'); + await page.focusNextElement(); + }, + }, + { + description: 'focus - container variant with interactive elements and description', + path: 'expandable-section/focus', + screenshotType: 'screenshotArea', + queryParams: { + headerText: 'Header text', + headerDescription: 'Header description', + hasHeaderInfo: 'true', + hasHeaderActions: 'true', + variant: 'container', + }, + setup: async ({ page }) => { + await page.click('#focus-target'); + await page.focusNextElement(); + }, + }, + { + description: 'stacked variant', + path: 'expandable-section/stacked-variant.permutations', + screenshotType: 'permutations', + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/file-dropzone.ts b/test/definitions/visual/file-dropzone.ts new file mode 100644 index 0000000000..5c845fa1ac --- /dev/null +++ b/test/definitions/visual/file-dropzone.ts @@ -0,0 +1,18 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'File dropzone', + componentName: 'file-dropzone', + tests: [ + { + description: 'In container', + path: 'file-dropzone/container', + screenshotType: 'screenshotArea', + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/file-input.ts b/test/definitions/visual/file-input.ts new file mode 100644 index 0000000000..c2d958d9c9 --- /dev/null +++ b/test/definitions/visual/file-input.ts @@ -0,0 +1,18 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'File input', + componentName: 'file-input', + tests: [ + { + description: 'Simple', + path: 'file-input/simple', + screenshotType: 'screenshotArea', + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/file-token-group.ts b/test/definitions/visual/file-token-group.ts new file mode 100644 index 0000000000..8aa68908d0 --- /dev/null +++ b/test/definitions/visual/file-token-group.ts @@ -0,0 +1,18 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'File token group', + componentName: 'file-token-group', + tests: [ + { + description: 'Permutations', + path: 'file-token-group/permutations', + screenshotType: 'permutations', + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/file-upload.ts b/test/definitions/visual/file-upload.ts new file mode 100644 index 0000000000..7426504608 --- /dev/null +++ b/test/definitions/visual/file-upload.ts @@ -0,0 +1,18 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'FileUpload', + componentName: 'file-upload', + tests: [ + { + description: 'Permutations', + path: 'file-upload/permutations', + screenshotType: 'permutations', + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/flashbar-stacked.ts b/test/definitions/visual/flashbar-stacked.ts new file mode 100644 index 0000000000..9b795791a6 --- /dev/null +++ b/test/definitions/visual/flashbar-stacked.ts @@ -0,0 +1,125 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'Flashbar stacked notifications', + componentName: 'flashbar', + tests: [ + { + description: '380px, collapsed', + path: 'flashbar/collapsible.visual-tests', + screenshotType: 'screenshotArea', + configuration: { width: 380 }, + }, + { + description: '380px, collapsed, notifications bar button focused', + path: 'flashbar/collapsible.visual-tests', + screenshotType: 'screenshotArea', + configuration: { width: 380 }, + setup: async ({ page }) => { + await page.click('#focus-target'); + await page.focusNextElement(); + }, + }, + { + description: '380px, expanded', + path: 'flashbar/collapsible.visual-tests', + screenshotType: 'screenshotArea', + configuration: { width: 380 }, + setup: async ({ page }) => { + await page.click('#focus-target'); + await page.focusNextElement(); + await page.keys(['Space']); + await new Promise(resolve => setTimeout(resolve, 500)); + }, + }, + { + description: '450px, collapsed', + path: 'flashbar/collapsible.visual-tests', + screenshotType: 'screenshotArea', + configuration: { width: 450 }, + }, + { + description: '450px, collapsed, notifications bar button focused', + path: 'flashbar/collapsible.visual-tests', + screenshotType: 'screenshotArea', + configuration: { width: 450 }, + setup: async ({ page }) => { + await page.click('#focus-target'); + await page.focusNextElement(); + }, + }, + { + description: '450px, expanded', + path: 'flashbar/collapsible.visual-tests', + screenshotType: 'screenshotArea', + configuration: { width: 450 }, + setup: async ({ page }) => { + await page.click('#focus-target'); + await page.focusNextElement(); + await page.keys(['Space']); + await new Promise(resolve => setTimeout(resolve, 500)); + }, + }, + { + description: '600px, collapsed', + path: 'flashbar/collapsible.visual-tests', + screenshotType: 'screenshotArea', + configuration: { width: 600 }, + }, + { + description: '600px, collapsed, notifications bar button focused', + path: 'flashbar/collapsible.visual-tests', + screenshotType: 'screenshotArea', + configuration: { width: 600 }, + setup: async ({ page }) => { + await page.click('#focus-target'); + await page.focusNextElement(); + }, + }, + { + description: '600px, expanded', + path: 'flashbar/collapsible.visual-tests', + screenshotType: 'screenshotArea', + configuration: { width: 600 }, + setup: async ({ page }) => { + await page.click('#focus-target'); + await page.focusNextElement(); + await page.keys(['Space']); + await new Promise(resolve => setTimeout(resolve, 500)); + }, + }, + { + description: '1200px, collapsed', + path: 'flashbar/collapsible.visual-tests', + screenshotType: 'screenshotArea', + configuration: { width: 1200 }, + }, + { + description: '1200px, collapsed, notifications bar button focused', + path: 'flashbar/collapsible.visual-tests', + screenshotType: 'screenshotArea', + configuration: { width: 1200 }, + setup: async ({ page }) => { + await page.click('#focus-target'); + await page.focusNextElement(); + }, + }, + { + description: '1200px, expanded', + path: 'flashbar/collapsible.visual-tests', + screenshotType: 'screenshotArea', + configuration: { width: 1200 }, + setup: async ({ page }) => { + await page.click('#focus-target'); + await page.focusNextElement(); + await page.keys(['Space']); + await new Promise(resolve => setTimeout(resolve, 500)); + }, + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/flashbar.ts b/test/definitions/visual/flashbar.ts new file mode 100644 index 0000000000..b620a4e031 --- /dev/null +++ b/test/definitions/visual/flashbar.ts @@ -0,0 +1,67 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'Flashbar', + componentName: 'flashbar', + tests: [ + { + description: 'permutations at 600', + path: 'flashbar/permutations', + screenshotType: 'permutations', + configuration: { width: 600 }, + }, + { + description: 'permutations at 1280', + path: 'flashbar/permutations', + screenshotType: 'permutations', + configuration: { width: 1280 }, + }, + { + description: 'runtime-action at 600', + path: 'flashbar/runtime-action', + screenshotType: 'permutations', + configuration: { width: 600 }, + }, + { + description: 'runtime-action at 1280', + path: 'flashbar/runtime-action', + screenshotType: 'permutations', + configuration: { width: 1280 }, + }, + { + description: 'content permutations', + path: 'flashbar/content-permutations', + screenshotType: 'permutations', + }, + { + description: 'style-custom', + path: 'flashbar/style-custom', + screenshotType: 'screenshotArea', + }, + { + description: 'small screen button layout', + path: 'flashbar/small-screen', + screenshotType: 'screenshotArea', + configuration: { width: 550 }, + }, + { + description: 'stacking of multiple flashbar items', + path: 'flashbar/stacking', + screenshotType: 'screenshotArea', + }, + { + description: 'focus border color', + path: 'flashbar/dismissal', + screenshotType: 'screenshotArea', + setup: async ({ page }) => { + await page.click('#focus-target'); + await page.focusNextElement(); + }, + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/form-field.ts b/test/definitions/visual/form-field.ts new file mode 100644 index 0000000000..59a207a24a --- /dev/null +++ b/test/definitions/visual/form-field.ts @@ -0,0 +1,61 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'FormField', + componentName: 'form-field', + tests: [ + { + description: 'Permutations at 576', + path: 'form-field/permutations', + screenshotType: 'permutations', + configuration: { width: 576 }, + }, + { + description: 'Scenarios at 576', + path: 'form-field/form-field-columns', + screenshotType: 'screenshotArea', + configuration: { width: 576 }, + }, + { + description: 'Permutations at 768', + path: 'form-field/permutations', + screenshotType: 'permutations', + configuration: { width: 768 }, + }, + { + description: 'Scenarios at 768', + path: 'form-field/form-field-columns', + screenshotType: 'screenshotArea', + configuration: { width: 768 }, + }, + { + description: 'Permutations at 992', + path: 'form-field/permutations', + screenshotType: 'permutations', + configuration: { width: 992 }, + }, + { + description: 'Scenarios at 992', + path: 'form-field/form-field-columns', + screenshotType: 'screenshotArea', + configuration: { width: 992 }, + }, + { + description: 'Permutations at 1200', + path: 'form-field/permutations', + screenshotType: 'permutations', + configuration: { width: 1200 }, + }, + { + description: 'Scenarios at 1200', + path: 'form-field/form-field-columns', + screenshotType: 'screenshotArea', + configuration: { width: 1200 }, + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/form.ts b/test/definitions/visual/form.ts new file mode 100644 index 0000000000..3a61c6e5a6 --- /dev/null +++ b/test/definitions/visual/form.ts @@ -0,0 +1,23 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'Form', + componentName: 'form', + tests: [ + { + description: 'permutations', + path: 'form/permutations', + screenshotType: 'permutations', + }, + { + description: 'simple', + path: 'form/simple', + screenshotType: 'screenshotArea', + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/grid.ts b/test/definitions/visual/grid.ts new file mode 100644 index 0000000000..299f2bb6e8 --- /dev/null +++ b/test/definitions/visual/grid.ts @@ -0,0 +1,37 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'Grid', + componentName: 'grid', + tests: [ + { + description: 'grid at "default"', + path: 'grid', + screenshotType: 'screenshotArea', + configuration: { width: 400 }, + }, + { + description: 'grid at "xs"', + path: 'grid', + screenshotType: 'screenshotArea', + configuration: { width: 800 }, + }, + { + description: 'grid at "m"', + path: 'grid', + screenshotType: 'screenshotArea', + configuration: { width: 1200 }, + }, + { + description: 'grid at "l"', + path: 'grid', + screenshotType: 'screenshotArea', + configuration: { width: 1400 }, + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/header.ts b/test/definitions/visual/header.ts new file mode 100644 index 0000000000..9643607963 --- /dev/null +++ b/test/definitions/visual/header.ts @@ -0,0 +1,67 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'Header', + componentName: 'header', + tests: [ + { + description: 'level-1 at 1500px', + path: 'header/level-1', + screenshotType: 'screenshotArea', + configuration: { width: 1500 }, + }, + { + description: 'level-1 at 850px', + path: 'header/level-1', + screenshotType: 'screenshotArea', + configuration: { width: 850 }, + }, + { + description: 'level-1 at 400px', + path: 'header/level-1', + screenshotType: 'screenshotArea', + configuration: { width: 400 }, + }, + { + description: 'level-2 at 1500px', + path: 'header/level-2', + screenshotType: 'screenshotArea', + configuration: { width: 1500 }, + }, + { + description: 'level-2 at 850px', + path: 'header/level-2', + screenshotType: 'screenshotArea', + configuration: { width: 850 }, + }, + { + description: 'level-2 at 400px', + path: 'header/level-2', + screenshotType: 'screenshotArea', + configuration: { width: 400 }, + }, + { + description: 'level-3 at 1500px', + path: 'header/level-3', + screenshotType: 'screenshotArea', + configuration: { width: 1500 }, + }, + { + description: 'level-3 at 850px', + path: 'header/level-3', + screenshotType: 'screenshotArea', + configuration: { width: 850 }, + }, + { + description: 'level-3 at 400px', + path: 'header/level-3', + screenshotType: 'screenshotArea', + configuration: { width: 400 }, + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/help-panel.ts b/test/definitions/visual/help-panel.ts new file mode 100644 index 0000000000..fabc497026 --- /dev/null +++ b/test/definitions/visual/help-panel.ts @@ -0,0 +1,28 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'HelpPanel', + componentName: 'help-panel', + tests: [ + { + description: 'permutations', + path: 'help-panel/permutations', + screenshotType: 'screenshotArea', + }, + { + description: 'with AppLayout', + path: 'help-panel/with-app-layout', + screenshotType: 'screenshotArea', + }, + { + description: 'loading state - with AppLayout', + path: 'help-panel/loading-with-app-layout', + screenshotType: 'screenshotArea', + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/icon.ts b/test/definitions/visual/icon.ts new file mode 100644 index 0000000000..bd8b064b35 --- /dev/null +++ b/test/definitions/visual/icon.ts @@ -0,0 +1,69 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'Icon', + componentName: 'icon', + tests: [ + { + description: 'Alignment with text', + path: 'icon/text-align', + screenshotType: 'screenshotArea', + configuration: { width: 300 }, + }, + { + description: 'Icons in normal variant', + path: 'icon/variant-normal', + screenshotType: 'screenshotArea', + }, + { + description: 'Icons in disabled variant', + path: 'icon/variant-disabled', + screenshotType: 'screenshotArea', + }, + { + description: 'Icons in error variant', + path: 'icon/variant-error', + screenshotType: 'screenshotArea', + }, + { + description: 'Icons in inverted variant', + path: 'icon/variant-inverted', + screenshotType: 'screenshotArea', + }, + { + description: 'Icons in subtle variant', + path: 'icon/variant-subtle', + screenshotType: 'screenshotArea', + }, + { + description: 'Icons in success variant', + path: 'icon/variant-success', + screenshotType: 'screenshotArea', + }, + { + description: 'Icons in warning variant', + path: 'icon/variant-warning', + screenshotType: 'screenshotArea', + }, + { + description: 'Custom icon', + path: 'icon/custom-icon', + screenshotType: 'screenshotArea', + }, + { + description: 'Custom svg icon', + path: 'icon/custom-svg', + screenshotType: 'screenshotArea', + }, + { + description: 'Inherit size property', + path: 'icon/size-inherit', + screenshotType: 'screenshotArea', + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/input.ts b/test/definitions/visual/input.ts new file mode 100644 index 0000000000..81c0145e88 --- /dev/null +++ b/test/definitions/visual/input.ts @@ -0,0 +1,23 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'Input', + componentName: 'input', + tests: [ + { + description: 'permutations', + path: 'input/permutations', + screenshotType: 'permutations', + }, + { + description: 'style-permutations', + path: 'input/style-permutations', + screenshotType: 'permutations', + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/item-card.ts b/test/definitions/visual/item-card.ts new file mode 100644 index 0000000000..bcf0439635 --- /dev/null +++ b/test/definitions/visual/item-card.ts @@ -0,0 +1,33 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'Item card', + componentName: 'item-card', + tests: [ + { + description: 'permutations', + path: 'item-card/permutations', + screenshotType: 'permutations', + }, + { + description: 'padding permutations', + path: 'item-card/padding-permutations', + screenshotType: 'permutations', + }, + { + description: 'variant permutations', + path: 'item-card/variant-permutations', + screenshotType: 'permutations', + }, + { + description: 'style-custom', + path: 'item-card/style-custom', + screenshotType: 'screenshotArea', + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/key-value-pairs.ts b/test/definitions/visual/key-value-pairs.ts new file mode 100644 index 0000000000..89dc9ec268 --- /dev/null +++ b/test/definitions/visual/key-value-pairs.ts @@ -0,0 +1,29 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'Key-value pairs', + componentName: 'key-value-pairs', + tests: [ + { + description: 'permutations', + path: 'key-value-pairs/permutations', + screenshotType: 'permutations', + }, + { + description: 'permutations on mobile (600px)', + path: 'key-value-pairs/permutations', + screenshotType: 'permutations', + configuration: { width: 600 }, + }, + { + description: 'wrapping text', + path: 'key-value-pairs/text-wrap', + screenshotType: 'screenshotArea', + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/line-chart.ts b/test/definitions/visual/line-chart.ts new file mode 100644 index 0000000000..560a355039 --- /dev/null +++ b/test/definitions/visual/line-chart.ts @@ -0,0 +1,156 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { TestSuite } from '../types'; + +const TEST_CHART_FILTER_TRIGGER = '#chart button'; +const TEST_CHART_TOOLTIP_HEADER = '#chart h2'; + +const suite: TestSuite = { + description: 'Line chart', + componentName: 'line-chart', + tests: [ + { + description: 'permutations', + path: 'line-chart/permutations', + screenshotType: 'permutations', + }, + { + description: 'can highlight all data points at a given X coordinate with keyboard', + path: 'line-chart/test', + screenshotType: 'viewport', + configuration: { width: 800, height: 800 }, + setup: async ({ page }) => { + await page.click(TEST_CHART_FILTER_TRIGGER); + await page.keys(['Escape']); + await page.focusNextElement(); + await page.keys(['ArrowRight', 'ArrowRight']); + await page.waitForVisible(TEST_CHART_TOOLTIP_HEADER); + }, + }, + { + description: 'can navigate series with keyboard', + path: 'line-chart/test', + screenshotType: 'viewport', + configuration: { width: 800, height: 800 }, + setup: async ({ page }) => { + await page.click(TEST_CHART_FILTER_TRIGGER); + await page.keys(['Escape']); + await page.focusNextElement(); + await page.keys(['ArrowRight', 'ArrowDown', 'ArrowRight']); + await page.waitForVisible(TEST_CHART_TOOLTIP_HEADER); + }, + }, + { + description: 'can pin popover for all data points at a given X coordinate with keyboard', + path: 'line-chart/test', + screenshotType: 'viewport', + configuration: { width: 800, height: 800 }, + pixelDiffTolerance: 6, + setup: async ({ page }) => { + await page.click(TEST_CHART_FILTER_TRIGGER); + await page.keys(['Escape']); + await page.focusNextElement(); + await page.keys(['ArrowRight', 'ArrowRight']); + await page.waitForVisible(TEST_CHART_TOOLTIP_HEADER); + await page.keys(['Enter']); + await page.waitForVisible('[aria-label="Dismiss"]'); + }, + }, + { + description: 'can pin popover for a point in a specific series with keyboard', + path: 'line-chart/test', + screenshotType: 'viewport', + configuration: { width: 800, height: 800 }, + setup: async ({ page }) => { + await page.click(TEST_CHART_FILTER_TRIGGER); + await page.keys(['Escape']); + await page.focusNextElement(); + await page.keys(['ArrowRight', 'ArrowDown', 'ArrowRight']); + await page.waitForVisible(TEST_CHART_TOOLTIP_HEADER); + await page.keys(['Enter']); + await page.waitForVisible('[aria-label="Dismiss"]'); + }, + }, + { + description: 'shows popover on hover', + path: 'line-chart/test', + screenshotType: 'viewport', + configuration: { width: 800, height: 800 }, + setup: async ({ page }) => { + await page.hoverElement('[aria-label="Line chart"]', 200, 50); + await page.waitForVisible(TEST_CHART_TOOLTIP_HEADER); + }, + }, + { + description: 'shows popover with expandable sub-items - no series highlighted, sub-items collapsed', + path: 'line-chart/drilldown', + screenshotType: 'screenshotArea', + configuration: { width: 800, height: 1000 }, + queryParams: { expandableSubItems: 'true' }, + setup: async ({ page, wrapper }) => { + await page.click('#focus-target'); + await page.focusNextElement(); + await page.keys(['ArrowRight']); + await page.waitForVisible(wrapper.findLineChart().findDetailPopover().toSelector()); + }, + }, + { + description: 'shows popover with expandable sub-items - no series highlighted, sub-items expanded', + path: 'line-chart/drilldown', + screenshotType: 'screenshotArea', + configuration: { width: 800, height: 1000 }, + queryParams: { expandableSubItems: 'true' }, + setup: async ({ page, wrapper }) => { + await page.click('#focus-target'); + await page.focusNextElement(); + await page.keys(['ArrowRight']); + await page.waitForVisible(wrapper.findLineChart().findDetailPopover().toSelector()); + await page.keys(['Tab']); + await page.keys(['Enter']); + }, + }, + { + description: 'shows popover with expandable sub-items - one series highlighted, sub-items collapsed', + path: 'line-chart/drilldown', + screenshotType: 'screenshotArea', + configuration: { width: 800, height: 1000 }, + queryParams: { expandableSubItems: 'true' }, + setup: async ({ page, wrapper }) => { + await page.click('#focus-target'); + await page.focusNextElement(); + await page.keys(['ArrowRight']); + await page.keys(['ArrowUp']); + await page.waitForVisible(wrapper.findLineChart().findDetailPopover().toSelector()); + }, + }, + { + description: 'shows popover with expandable sub-items - one series highlighted, sub-items expanded', + path: 'line-chart/drilldown', + screenshotType: 'screenshotArea', + configuration: { width: 800, height: 1000 }, + queryParams: { expandableSubItems: 'true' }, + setup: async ({ page, wrapper }) => { + await page.click('#focus-target'); + await page.focusNextElement(); + await page.keys(['ArrowRight']); + await page.keys(['ArrowUp']); + await page.waitForVisible(wrapper.findLineChart().findDetailPopover().toSelector()); + await page.keys(['Tab']); + await page.keys(['Enter']); + }, + }, + { + description: 'correctly renders the chart inside an expandable section - X ticks do not overlap nor overflow', + path: 'line-chart/in-expandable-section-test', + screenshotType: 'screenshotArea', + configuration: { width: 800, height: 800 }, + setup: async ({ page, wrapper }) => { + const expandableSectionWrapper = wrapper.findExpandableSection(); + await page.waitForVisible(expandableSectionWrapper.toSelector()); + await page.click(expandableSectionWrapper.findExpandButton().toSelector()); + }, + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/link.ts b/test/definitions/visual/link.ts new file mode 100644 index 0000000000..c381876e14 --- /dev/null +++ b/test/definitions/visual/link.ts @@ -0,0 +1,38 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'Link', + componentName: 'link', + tests: [ + { + description: 'Permutations', + path: 'link/permutations', + screenshotType: 'permutations', + }, + { + description: 'Permutations (long label)', + path: 'link/long-label-permutations', + screenshotType: 'permutations', + }, + { + description: 'Icon overflow permutations', + path: 'link/icon-overflow-permutations', + screenshotType: 'permutations', + }, + { + description: 'Inherit font size permutations', + path: 'link/inherit-permutations', + screenshotType: 'permutations', + }, + { + description: 'Style custom page', + path: 'link/style-custom-types', + screenshotType: 'screenshotArea', + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/list.ts b/test/definitions/visual/list.ts new file mode 100644 index 0000000000..9dbe349f8c --- /dev/null +++ b/test/definitions/visual/list.ts @@ -0,0 +1,23 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'List', + componentName: 'list', + tests: [ + { + description: 'permutations', + path: 'list/permutations', + screenshotType: 'permutations', + }, + { + description: 'sortable-permutations', + path: 'list/sortable-permutations', + screenshotType: 'permutations', + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/mixed-line-bar-chart.ts b/test/definitions/visual/mixed-line-bar-chart.ts new file mode 100644 index 0000000000..d97a37a9d2 --- /dev/null +++ b/test/definitions/visual/mixed-line-bar-chart.ts @@ -0,0 +1,110 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const TEST_CHART_TOOLTIP_HEADER = '#chart h2'; + +const suite: TestSuite = { + description: 'Mixed line bar chart', + componentName: 'mixed-line-bar-chart', + tests: [ + { + description: 'permutations', + path: 'mixed-line-bar-chart/permutations', + screenshotType: 'permutations', + }, + { + description: 'fit-height', + path: 'mixed-line-bar-chart/fit-height', + screenshotType: 'screenshotArea', + }, + { + description: 'fit-height no filter, no legend', + path: 'mixed-line-bar-chart/fit-height', + screenshotType: 'screenshotArea', + queryParams: { hideFilter: 'true', hideLegend: 'true' }, + }, + { + description: 'fit-height, no legend', + path: 'mixed-line-bar-chart/fit-height', + screenshotType: 'screenshotArea', + queryParams: { hideLegend: 'true' }, + }, + { + description: 'chart plot has a focus outline', + path: 'mixed-line-bar-chart/test', + screenshotType: 'viewport', + configuration: { width: 800, height: 800 }, + setup: async ({ page }) => { + await page.click('#focus-target'); + await page.focusNextElement(); + await page.focusNextElement(); + }, + }, + { + description: 'can navigate series with keyboard', + path: 'mixed-line-bar-chart/test', + screenshotType: 'viewport', + configuration: { width: 800, height: 800 }, + pixelDiffTolerance: 12, + setup: async ({ page }) => { + await page.click('#focus-target'); + await page.focusNextElement(); + await page.focusNextElement(); + await page.keys(['ArrowRight']); + await page.keys(['ArrowRight']); + await page.keys(['ArrowRight']); + await page.waitForVisible(TEST_CHART_TOOLTIP_HEADER); + }, + }, + { + description: 'can pin popover with keyboard', + path: 'mixed-line-bar-chart/test', + screenshotType: 'viewport', + configuration: { width: 800, height: 800 }, + pixelDiffTolerance: 12, + setup: async ({ page }) => { + await page.click('#focus-target'); + await page.focusNextElement(); + await page.focusNextElement(); + await page.keys(['ArrowRight']); + await page.keys(['ArrowRight']); + await page.keys(['ArrowRight']); + await page.waitForVisible(TEST_CHART_TOOLTIP_HEADER); + await page.keys(['Enter']); + await page.waitForVisible('[aria-label="Dismiss"]'); + }, + }, + { + description: 'shows popover on hover', + path: 'mixed-line-bar-chart/test', + screenshotType: 'viewport', + configuration: { width: 800, height: 800 }, + setup: async ({ page }) => { + await page.hoverElement('#chart svg[aria-label="Mixed chart 1"]', 200, 100); + await page.waitForVisible(TEST_CHART_TOOLTIP_HEADER); + }, + }, + { + description: 'handles long left-labels at width 320px', + path: 'mixed-line-bar-chart/with-long-left-labels', + screenshotType: 'screenshotArea', + configuration: { width: 320 }, + }, + { + description: 'handles long left-labels at width 400px', + path: 'mixed-line-bar-chart/with-long-left-labels', + screenshotType: 'screenshotArea', + configuration: { width: 400 }, + }, + { + description: 'handles long left-labels at width 600px', + path: 'mixed-line-bar-chart/with-long-left-labels', + screenshotType: 'screenshotArea', + configuration: { width: 600 }, + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/modal.ts b/test/definitions/visual/modal.ts new file mode 100644 index 0000000000..28fb043c6d --- /dev/null +++ b/test/definitions/visual/modal.ts @@ -0,0 +1,163 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'Modal', + componentName: 'modal', + tests: [ + { + description: 'simple', + path: 'modal/simple', + screenshotType: 'viewport', + setup: async ({ page }) => { + await page.click('aria/Show modal'); + }, + }, + { + description: 'no-paddings', + path: 'modal/no-paddings', + screenshotType: 'viewport', + setup: async ({ page }) => { + await page.click('aria/Show modal'); + }, + }, + { + description: 'vertical-scroll', + path: 'modal/vertical-scroll', + screenshotType: 'viewport', + setup: async ({ page }) => { + await page.click('aria/Show modal'); + }, + }, + { + description: 'long-header', + path: 'modal/long-header', + screenshotType: 'viewport', + setup: async ({ page }) => { + await page.click('aria/Show modal'); + }, + }, + { + description: 'unbreakable-header', + path: 'modal/unbreakable-header', + screenshotType: 'viewport', + setup: async ({ page }) => { + await page.click('aria/Show modal'); + }, + }, + { + description: 'size-small', + path: 'modal/sizes', + screenshotType: 'viewport', + setup: async ({ page }) => { + await page.click('aria/small'); + }, + }, + { + description: 'size-medium', + path: 'modal/sizes', + screenshotType: 'viewport', + setup: async ({ page }) => { + await page.click('aria/medium'); + }, + }, + { + description: 'size-large', + path: 'modal/sizes', + screenshotType: 'viewport', + setup: async ({ page }) => { + await page.click('aria/large'); + }, + }, + { + description: 'size-x-large', + path: 'modal/sizes', + screenshotType: 'viewport', + setup: async ({ page }) => { + await page.click('aria/x-large'); + }, + }, + { + description: 'size-xx-large', + path: 'modal/sizes', + screenshotType: 'viewport', + setup: async ({ page }) => { + await page.click('aria/xx-large'); + }, + }, + { + description: 'size-max', + path: 'modal/sizes', + screenshotType: 'viewport', + setup: async ({ page }) => { + await page.click('aria/max'); + }, + }, + { + description: 'position-top', + path: 'modal/position-top', + screenshotType: 'viewport', + setup: async ({ page }) => { + await page.click('aria/Show modal'); + }, + }, + { + description: 'custom-dimensions with footer', + path: 'modal/custom-dimensions', + screenshotType: 'viewport', + queryParams: { width: '600', height: '400', footer: 'true' }, + setup: async ({ page }) => { + await page.click('[data-testid="modal-trigger"]'); + }, + }, + { + description: 'custom-dimensions without footer', + path: 'modal/custom-dimensions', + screenshotType: 'viewport', + queryParams: { width: '600', height: '400', footer: 'false' }, + setup: async ({ page }) => { + await page.click('[data-testid="modal-trigger"]'); + }, + }, + { + description: 'custom-dimensions very small width', + path: 'modal/custom-dimensions', + screenshotType: 'viewport', + queryParams: { width: '10' }, + setup: async ({ page }) => { + await page.click('[data-testid="modal-trigger"]'); + }, + }, + { + description: 'custom-dimensions very small height with footer', + path: 'modal/custom-dimensions', + screenshotType: 'viewport', + queryParams: { height: '10', footer: 'true' }, + setup: async ({ page }) => { + await page.click('[data-testid="modal-trigger"]'); + }, + }, + { + description: 'custom-dimensions very small height & width with footer', + path: 'modal/custom-dimensions', + screenshotType: 'viewport', + queryParams: { width: '10', height: '15', footer: 'true' }, + setup: async ({ page }) => { + await page.click('[data-testid="modal-trigger"]'); + }, + }, + { + description: 'custom-dimensions large height & width with footer', + path: 'modal/custom-dimensions', + screenshotType: 'viewport', + queryParams: { width: '10000', height: '10000', footer: 'true' }, + setup: async ({ page }) => { + await page.click('[data-testid="modal-trigger"]'); + }, + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/multiselect.ts b/test/definitions/visual/multiselect.ts new file mode 100644 index 0000000000..d08b3b06b8 --- /dev/null +++ b/test/definitions/visual/multiselect.ts @@ -0,0 +1,136 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'Multiselect', + componentName: 'multiselect', + tests: [ + { + description: 'permutations', + path: 'multiselect/permutations', + screenshotType: 'permutations', + }, + { + description: 'inlineLabelText-permutations', + path: 'multiselect/inline-label-text-permutations', + screenshotType: 'permutations', + }, + { + description: 'expandToViewport=true virtualScroll=true filteringType=manual', + path: 'multiselect/screenshot', + screenshotType: 'screenshotArea', + queryParams: { expandToViewport: 'true', virtualScroll: 'true', filteringType: 'manual' }, + setup: async ({ page, wrapper }) => { + await page.click(wrapper.findMultiselect().findTrigger().toSelector()); + }, + }, + { + description: 'expandToViewport=true virtualScroll=true filteringType=auto', + path: 'multiselect/screenshot', + screenshotType: 'screenshotArea', + queryParams: { expandToViewport: 'true', virtualScroll: 'true', filteringType: 'auto' }, + setup: async ({ page, wrapper }) => { + await page.click(wrapper.findMultiselect().findTrigger().toSelector()); + }, + }, + { + description: 'expandToViewport=true virtualScroll=true filteringType=none', + path: 'multiselect/screenshot', + screenshotType: 'screenshotArea', + queryParams: { expandToViewport: 'true', virtualScroll: 'true', filteringType: 'none' }, + setup: async ({ page, wrapper }) => { + await page.click(wrapper.findMultiselect().findTrigger().toSelector()); + }, + }, + { + description: 'expandToViewport=false virtualScroll=false filteringType=manual', + path: 'multiselect/screenshot', + screenshotType: 'screenshotArea', + queryParams: { expandToViewport: 'false', virtualScroll: 'false', filteringType: 'manual' }, + setup: async ({ page, wrapper }) => { + await page.click(wrapper.findMultiselect().findTrigger().toSelector()); + }, + }, + { + description: 'error status wrapping - normal list', + path: 'multiselect/screenshot', + screenshotType: 'screenshotArea', + queryParams: { statusType: 'error' }, + setup: async ({ page, wrapper }) => { + await page.click(wrapper.findMultiselect().findTrigger().toSelector()); + }, + }, + { + description: 'item selected (dropdown stays open) - normal list', + path: 'multiselect/screenshot', + screenshotType: 'screenshotArea', + queryParams: { virtualScroll: 'false' }, + setup: async ({ page, wrapper }) => { + await page.click(wrapper.findMultiselect().findTrigger().toSelector()); + await page.click('[data-test-index="4"]'); + }, + }, + { + description: 'item selected (dropdown stays open) - virtual list', + path: 'multiselect/screenshot', + screenshotType: 'screenshotArea', + queryParams: { virtualScroll: 'true' }, + setup: async ({ page, wrapper }) => { + await page.click(wrapper.findMultiselect().findTrigger().toSelector()); + await page.click('[data-test-index="4"]'); + }, + }, + { + description: 'custom render option - normal list', + path: 'multiselect/custom-render-option', + screenshotType: 'screenshotArea', + queryParams: { virtualScroll: 'false' }, + setup: async ({ page, wrapper }) => { + await page.click(wrapper.findMultiselect().findTrigger().toSelector()); + }, + }, + { + description: 'custom render option - virtual list', + path: 'multiselect/custom-render-option', + screenshotType: 'screenshotArea', + queryParams: { virtualScroll: 'true' }, + setup: async ({ page, wrapper }) => { + await page.click(wrapper.findMultiselect().findTrigger().toSelector()); + }, + }, + { + description: 'Long virtual list - navigate to last item', + path: 'multiselect/virtual-scroll', + screenshotType: 'screenshotArea', + queryParams: { type: 'multiselect' }, + setup: async ({ page, wrapper }) => { + const triggerSelector = wrapper.findMultiselect().findTrigger().toSelector(); + page.waitForVisible(triggerSelector); + await page.click(triggerSelector); + await page.elementScrollTo(wrapper.findMultiselect().findDropdown().findOptionsContainer().toSelector(), { + top: 99999, + }); + await page.waitForJsTimers(); + }, + }, + { + description: 'Long virtual list (select all) - navigate to last item', + path: 'multiselect/virtual-scroll', + screenshotType: 'screenshotArea', + queryParams: { type: 'multiselect-select-all' }, + setup: async ({ page, wrapper }) => { + const triggerSelector = wrapper.findMultiselect().findTrigger().toSelector(); + page.waitForVisible(triggerSelector); + await page.click(triggerSelector); + await page.elementScrollTo(wrapper.findMultiselect().findDropdown().findOptionsContainer().toSelector(), { + top: 99999, + }); + await page.waitForJsTimers(); + }, + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/pagination.ts b/test/definitions/visual/pagination.ts new file mode 100644 index 0000000000..ed8ec25aee --- /dev/null +++ b/test/definitions/visual/pagination.ts @@ -0,0 +1,18 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'Pagination', + componentName: 'pagination', + tests: [ + { + description: 'permutations', + path: 'pagination/permutations', + screenshotType: 'permutations', + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/pie-chart.ts b/test/definitions/visual/pie-chart.ts new file mode 100644 index 0000000000..ee92299a71 --- /dev/null +++ b/test/definitions/visual/pie-chart.ts @@ -0,0 +1,66 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'Pie chart', + componentName: 'pie-chart', + tests: [ + { + description: 'permutations', + path: 'pie-chart/permutations', + screenshotType: 'permutations', + }, + { + description: 'permutations in narrow container', + path: 'pie-chart/permutations', + screenshotType: 'permutations', + configuration: { width: 350 }, + }, + { + description: 'fit-height', + path: 'pie-chart/fit-height', + screenshotType: 'screenshotArea', + }, + { + description: 'fit-height no filter, no legend', + path: 'pie-chart/fit-height', + screenshotType: 'screenshotArea', + queryParams: { hideFilter: 'true', hideLegend: 'true' }, + }, + { + description: 'can focus chart plot', + path: 'pie-chart/test', + screenshotType: 'screenshotArea', + setup: async ({ page }) => { + await page.click('#focus-target'); + await page.focusNextElement(); + await page.focusNextElement(); + }, + }, + { + description: 'can navigate segments with keyboard', + path: 'pie-chart/test', + screenshotType: 'screenshotArea', + setup: async ({ page }) => { + await page.click('#focus-target'); + await page.focusNextElement(); + await page.focusNextElement(); + await page.keys(['Enter']); + await page.keys(['ArrowRight']); + }, + }, + { + description: 'can pin segments with mouse', + path: 'pie-chart/test', + screenshotType: 'screenshotArea', + setup: async ({ page }) => { + await page.click('svg [aria-label~="Apples"] > path'); + await page.waitForVisible('[aria-label="Dismiss"]'); + }, + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/popover.ts b/test/definitions/visual/popover.ts new file mode 100644 index 0000000000..1acd509b76 --- /dev/null +++ b/test/definitions/visual/popover.ts @@ -0,0 +1,197 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'Popover', + componentName: 'popover', + tests: [ + { + description: 'text wrapping', + path: 'popover/text-wrap', + screenshotType: 'screenshotArea', + }, + { + description: 'alignment inside text', + path: 'popover/text-align', + screenshotType: 'screenshotArea', + }, + { + description: 'inside modal', + path: 'popover/scenario-in-modal', + screenshotType: 'viewport', + setup: async ({ page }) => { + await page.click('aria/Show modal'); + await page.click('#popover button'); + }, + }, + { + description: 'positioning with navigation v1.0', + path: 'popover/nav-v1-0-positioning', + screenshotType: 'viewport', + setup: async ({ page }) => { + await page.click('#popover button'); + }, + }, + { + description: 'close icon positioned inside the popover (no header and fixed width)', + path: 'popover/header-variant', + screenshotType: 'viewport', + setup: async ({ page }) => { + await page.click('[data-testid="popover-without-title"] button'); + }, + }, + { + description: 'inside table - renderWithPortal=false', + path: 'popover/scenario-in-table', + screenshotType: 'viewport', + setup: async ({ page }) => { + await page.click('table button'); + }, + }, + { + description: 'inside table - renderWithPortal=true', + path: 'popover/scenario-in-table', + screenshotType: 'viewport', + setup: async ({ page }) => { + await page.click('#renderWithPortal'); + await page.click('table button'); + }, + }, + { + description: 'scenario - copy - renderWithPortal=false', + path: 'popover/scenarios', + screenshotType: 'viewport', + setup: async ({ page }) => { + await page.click('#scenario-copy button'); + }, + }, + { + description: 'scenario - copy - renderWithPortal=true', + path: 'popover/scenarios', + screenshotType: 'viewport', + setup: async ({ page }) => { + await page.click('#renderWithPortal'); + await page.click('#scenario-copy button'); + }, + }, + { + description: 'scenario - medium-key-value - renderWithPortal=false', + path: 'popover/scenarios', + screenshotType: 'viewport', + setup: async ({ page }) => { + await page.click('#scenario-medium-key-value button'); + }, + }, + { + description: 'scenario - large-key-value - renderWithPortal=false', + path: 'popover/scenarios', + screenshotType: 'viewport', + setup: async ({ page }) => { + await page.click('#scenario-large-key-value button'); + }, + }, + { + description: 'inline popover - closed - renderWithPortal=false', + path: 'popover/inline', + screenshotType: 'screenshotArea', + }, + { + description: 'inline popover - closed - renderWithPortal=true', + path: 'popover/inline', + screenshotType: 'screenshotArea', + setup: async ({ page }) => { + await page.click('#renderWithPortal'); + }, + }, + { + description: 'inline popover - open - renderWithPortal=false', + path: 'popover/inline', + screenshotType: 'screenshotArea', + setup: async ({ page, wrapper }) => { + await page.click(wrapper.findPopover().findTrigger().toSelector()); + }, + }, + { + description: 'inline popover - open - renderWithPortal=true', + path: 'popover/inline', + screenshotType: 'screenshotArea', + setup: async ({ page, wrapper }) => { + await page.click('#renderWithPortal'); + await page.click(wrapper.findPopover().findTrigger().toSelector()); + }, + }, + { + description: 'positioning - opens in the correct position - renderWithPortal=false', + path: 'popover/positioning', + screenshotType: 'viewport', + setup: async ({ page }) => { + await page.click('#popover-2-2 button'); + }, + }, + { + description: 'positioning - flips to the opposite position - renderWithPortal=false', + path: 'popover/positioning', + screenshotType: 'viewport', + setup: async ({ page }) => { + await page.click('#popover-1-2 button'); + }, + }, + { + description: 'focus - Permutation 1', + path: 'popover/focus-ring', + screenshotType: 'screenshotArea', + setup: async ({ page }) => { + await page.click('#focus-target'); + await page.focusNextElement(); + }, + }, + { + description: 'focus - Permutation 2', + path: 'popover/focus-ring', + screenshotType: 'screenshotArea', + setup: async ({ page }) => { + await page.click('#focus-target'); + for (let j = 0; j < 2; j++) { + await page.focusNextElement(); + } + }, + }, + { + description: 'focus - Permutation 3', + path: 'popover/focus-ring', + screenshotType: 'screenshotArea', + setup: async ({ page }) => { + await page.click('#focus-target'); + for (let j = 0; j < 3; j++) { + await page.focusNextElement(); + } + }, + }, + { + description: 'focus - Permutation 6', + path: 'popover/focus-ring', + screenshotType: 'screenshotArea', + setup: async ({ page }) => { + await page.click('#focus-target'); + for (let j = 0; j < 6; j++) { + await page.focusNextElement(); + } + }, + }, + { + description: 'focus - Permutation 12', + path: 'popover/focus-ring', + screenshotType: 'screenshotArea', + setup: async ({ page }) => { + await page.click('#focus-target'); + for (let j = 0; j < 12; j++) { + await page.focusNextElement(); + } + }, + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/progress-bar.ts b/test/definitions/visual/progress-bar.ts new file mode 100644 index 0000000000..1280b00599 --- /dev/null +++ b/test/definitions/visual/progress-bar.ts @@ -0,0 +1,31 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'ProgressBar', + componentName: 'progress-bar', + tests: [ + { + description: 'permutations - standalone', + path: 'progress-bar/permutations-standalone', + screenshotType: 'permutations', + configuration: { width: 800 }, + }, + { + description: 'permutations - flash', + path: 'progress-bar/permutations-flash', + screenshotType: 'screenshotArea', + configuration: { width: 800 }, + }, + { + description: 'permutations - key-value', + path: 'progress-bar/permutations-key-value', + screenshotType: 'screenshotArea', + configuration: { width: 800 }, + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/prompt-input.ts b/test/definitions/visual/prompt-input.ts new file mode 100644 index 0000000000..536f1a10d9 --- /dev/null +++ b/test/definitions/visual/prompt-input.ts @@ -0,0 +1,46 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'PromptInput', + componentName: 'prompt-input', + tests: [ + { + description: 'Permutations at 250', + path: 'prompt-input/permutations', + screenshotType: 'permutations', + configuration: { width: 250 }, + }, + { + description: 'Permutations at 400', + path: 'prompt-input/permutations', + screenshotType: 'permutations', + configuration: { width: 400 }, + }, + { + description: 'Permutations at 800', + path: 'prompt-input/permutations', + screenshotType: 'permutations', + configuration: { width: 800 }, + }, + { + description: 'Style Permutations', + path: 'prompt-input/style-permutations', + screenshotType: 'permutations', + }, + { + description: 'focus ring on the last secondary action', + path: 'prompt-input/simple', + screenshotType: 'screenshotArea', + queryParams: { hasSecondaryActions: 'true' }, + setup: async ({ page, wrapper }) => { + await page.click(wrapper.findPromptInput('[data-testid="prompt-input"]').findNativeTextarea().toSelector()); + await page.keys(['Tab', 'ArrowRight', 'ArrowRight']); + }, + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/property-filter.ts b/test/definitions/visual/property-filter.ts new file mode 100644 index 0000000000..ef96c61725 --- /dev/null +++ b/test/definitions/visual/property-filter.ts @@ -0,0 +1,144 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'Property filter', + componentName: 'property-filter', + tests: [ + { + description: 'token editor popover', + path: 'property-filter/token-editor', + screenshotType: 'screenshotArea', + setup: async ({ page }) => { + await page.click('.property-filter-default [aria-haspopup=dialog]'); + }, + }, + { + description: 'filtering token select', + path: 'property-filter/token-editor', + screenshotType: 'screenshotArea', + setup: async ({ page }) => { + await page.click('.property-filter-default [aria-haspopup=listbox]'); + }, + }, + { + description: 'token editor popover overflow', + path: 'property-filter/token-editor', + screenshotType: 'screenshotArea', + setup: async ({ page }) => { + await page.click('.property-filter-overflow [aria-haspopup=dialog]'); + }, + }, + { + description: 'token editor custom property boolean', + path: 'property-filter/token-editor', + screenshotType: 'screenshotArea', + setup: async ({ page }) => { + await page.click('.property-filter-custom-prop-boolean [aria-haspopup=dialog]'); + }, + }, + { + description: 'token editor custom property datetime', + path: 'property-filter/token-editor', + screenshotType: 'screenshotArea', + setup: async ({ page }) => { + await page.click('.property-filter-custom-prop-datetime [aria-haspopup=dialog]'); + }, + }, + { + description: 'token editor group string property', + path: 'property-filter/token-editor', + screenshotType: 'screenshotArea', + setup: async ({ page, wrapper }) => { + const propertyFilter = wrapper.findPropertyFilter('.property-filter-group-editor'); + await page.click(propertyFilter.findTokens().get(1).findLabel().toSelector()); + }, + }, + { + description: 'token editor group datetime property', + path: 'property-filter/token-editor', + screenshotType: 'screenshotArea', + setup: async ({ page, wrapper }) => { + const propertyFilter = wrapper.findPropertyFilter('.property-filter-group-editor'); + await page.click(propertyFilter.findTokens().get(1).findLabel().toSelector()); + await page.keys(['Escape']); + await page.keys(['Tab', 'Tab', 'Tab', 'Enter']); + }, + }, + { + description: 'token editor enum property', + path: 'property-filter/token-editor', + screenshotType: 'screenshotArea', + setup: async ({ page, wrapper }) => { + const propertyFilter = wrapper.findPropertyFilter('.property-filter-group-editor'); + await page.click(propertyFilter.findNativeInput().toSelector()); + await page.keys('state = s'); + }, + }, + { + description: 'token editor enum property no matches', + path: 'property-filter/token-editor', + screenshotType: 'screenshotArea', + setup: async ({ page, wrapper }) => { + const propertyFilter = wrapper.findPropertyFilter('.property-filter-group-editor'); + await page.click(propertyFilter.findNativeInput().toSelector()); + await page.keys('state = x'); + }, + }, + { + description: 'permutations', + path: 'property-filter/permutations', + screenshotType: 'permutations', + }, + { + description: 'tokens permutations', + path: 'property-filter/property-filter-tokens-permutations', + screenshotType: 'permutations', + }, + { + description: 'editor permutations at 400', + path: 'property-filter/property-filter-editor-permutations', + screenshotType: 'permutations', + configuration: { width: 400 }, + }, + { + description: 'editor permutations at 1200', + path: 'property-filter/property-filter-editor-permutations', + screenshotType: 'permutations', + configuration: { width: 1200 }, + }, + { + description: 'split panel integration - main content dropdown', + path: 'property-filter/split-panel-app-layout-integration', + screenshotType: 'viewport', + setup: async ({ page }) => { + await page.click('.main-content input[aria-label="your choice"]'); + }, + }, + { + description: 'split panel integration - main content popover', + path: 'property-filter/split-panel-app-layout-integration', + screenshotType: 'viewport', + setup: async ({ page }) => { + await page.click('.main-content button[aria-haspopup=dialog]'); + }, + }, + { + description: 'virtual scroll navigate through 100 items', + path: 'property-filter/virtual-scroll', + screenshotType: 'screenshotArea', + setup: async ({ page, wrapper }) => { + const propertyFilter = wrapper.findPropertyFilter(); + await page.click(propertyFilter.findNativeInput().toSelector()); + await page.keys('Property = '); + for (let i = 0; i < 100; i++) { + await page.keys('ArrowDown'); + } + }, + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/radio-button.ts b/test/definitions/visual/radio-button.ts new file mode 100644 index 0000000000..5554d51057 --- /dev/null +++ b/test/definitions/visual/radio-button.ts @@ -0,0 +1,42 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'RadioButton', + componentName: 'radio-button', + tests: [ + { + description: 'Permutations', + path: 'radio-button/permutations', + screenshotType: 'permutations', + }, + { + description: 'Focused and not checked', + path: 'radio-button/focus-test', + screenshotType: 'screenshotArea', + setup: async ({ page }) => { + await page.click('#focus-target'); + await page.focusNextElement(); + }, + }, + { + description: 'Focused and checked', + path: 'radio-button/focus-test', + screenshotType: 'screenshotArea', + setup: async ({ page }) => { + await page.click('#focus-target'); + await page.focusNextElement(); + await page.keys(['Space']); + }, + }, + { + description: 'Custom style permutations', + path: 'radio-button/style-custom', + screenshotType: 'permutations', + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/radio-group.ts b/test/definitions/visual/radio-group.ts new file mode 100644 index 0000000000..49bfbcdc32 --- /dev/null +++ b/test/definitions/visual/radio-group.ts @@ -0,0 +1,49 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'RadioGroup', + componentName: 'radio-group', + tests: [ + { + description: 'Permutations', + path: 'radio-group/permutations', + screenshotType: 'permutations', + }, + { + description: 'Radio button is focused', + path: 'radio-group/focus-test', + screenshotType: 'screenshotArea', + setup: async ({ page }) => { + await page.click('#focus-target'); + await page.focusNextElement(); + }, + }, + { + description: 'Radio button has label with a correct width', + path: 'radio-group/labels-highlight', + screenshotType: 'screenshotArea', + }, + { + description: 'Horizontal radio group permutations at 600', + path: 'radio-group/horizontal.permutations', + screenshotType: 'permutations', + configuration: { width: 600 }, + }, + { + description: 'Horizontal radio group permutations at 1280', + path: 'radio-group/horizontal.permutations', + screenshotType: 'permutations', + configuration: { width: 1280 }, + }, + { + description: 'Style custom page', + path: 'radio-group/style-custom', + screenshotType: 'screenshotArea', + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/s3-resource-selector.ts b/test/definitions/visual/s3-resource-selector.ts new file mode 100644 index 0000000000..54c39daada --- /dev/null +++ b/test/definitions/visual/s3-resource-selector.ts @@ -0,0 +1,38 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'S3 Resource Selector', + componentName: 's3-resource-selector', + tests: [ + { + description: 'Permutations', + path: 's3-resource-selector/permutations', + screenshotType: 'permutations', + }, + { + description: 'Browse dialog - plain', + path: 's3-resource-selector/permutations', + screenshotType: 'viewport', + configuration: { height: 1000 }, + setup: async ({ page }) => { + await page.click('button=Browse S3'); + await page.waitForVisible('[role="dialog"]'); + }, + }, + { + description: 'Browse dialog - with alert', + path: 's3-resource-selector/with-alert', + screenshotType: 'viewport', + configuration: { height: 1100 }, + setup: async ({ page }) => { + await page.click('button=Browse S3'); + await page.waitForVisible('[role="dialog"]'); + }, + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/segmented-control.ts b/test/definitions/visual/segmented-control.ts new file mode 100644 index 0000000000..5be8493c37 --- /dev/null +++ b/test/definitions/visual/segmented-control.ts @@ -0,0 +1,23 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'SegmentedControl', + componentName: 'segmented-control', + tests: [ + { + description: 'Permutations', + path: 'segmented-control/permutations', + screenshotType: 'permutations', + }, + { + description: 'Style Permutations', + path: 'segmented-control/style-permutations', + screenshotType: 'permutations', + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/select.ts b/test/definitions/visual/select.ts new file mode 100644 index 0000000000..84d6b3ac04 --- /dev/null +++ b/test/definitions/visual/select.ts @@ -0,0 +1,96 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'Select', + componentName: 'select', + tests: [ + { + description: 'component - dropdown closed', + path: 'select/screenshot', + screenshotType: 'screenshotArea', + }, + { + description: 'component - dropdown open - plain list', + path: 'select/screenshot', + screenshotType: 'screenshotArea', + setup: async ({ page }) => { + await page.click('[data-testid="select-demo"] button'); + }, + }, + { + description: 'component - dropdown open - virtual list', + path: 'select/screenshot', + screenshotType: 'screenshotArea', + setup: async ({ page }) => { + await page.click('#toggle-virtual'); + await page.click('[data-testid="select-demo"] button'); + }, + }, + { + description: 'component - dropdown open limited width - plain list', + path: 'select/screenshot', + screenshotType: 'screenshotArea', + setup: async ({ page }) => { + await page.click('[data-testid="select-demo-with-no-filtering-and-limited-width"] button'); + }, + }, + { + description: 'keyboard interaction - plain list', + path: 'select/screenshot', + screenshotType: 'screenshotArea', + setup: async ({ page }) => { + await page.click('[data-testid="select-demo-no-filtering"] button'); + await page.keys(['ArrowDown', 'Space']); + }, + }, + { + description: 'component - custom render option - plain list', + path: 'select/custom-render-option', + screenshotType: 'screenshotArea', + queryParams: { virtualScroll: 'false' }, + setup: async ({ page, wrapper }) => { + await page.click(wrapper.findSelect().findTrigger().toSelector()); + }, + }, + { + description: 'component - custom render option - virtual list', + path: 'select/custom-render-option', + screenshotType: 'screenshotArea', + queryParams: { virtualScroll: 'true' }, + setup: async ({ page, wrapper }) => { + await page.click(wrapper.findSelect().findTrigger().toSelector()); + }, + }, + { + description: 'item permutations', + path: 'select/item.permutations', + screenshotType: 'permutations', + }, + { + description: 'selectable-item permutations', + path: 'selectable-item/permutations', + screenshotType: 'permutations', + }, + { + description: 'trigger permutations', + path: 'select/trigger.permutations', + screenshotType: 'permutations', + }, + { + description: 'Long virtual list - navigate to last item', + path: 'select/virtual-scroll', + screenshotType: 'screenshotArea', + setup: async ({ page, wrapper }) => { + await page.click(wrapper.findSelect().findTrigger().toSelector()); + await page.elementScrollTo(wrapper.findSelect().findDropdown().findOptionsContainer().toSelector(), { + top: 99999, + }); + }, + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/side-navigation.ts b/test/definitions/visual/side-navigation.ts new file mode 100644 index 0000000000..fce8be8eb1 --- /dev/null +++ b/test/definitions/visual/side-navigation.ts @@ -0,0 +1,18 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'SideNavigation', + componentName: 'side-navigation', + tests: [ + { + description: 'Permutations', + path: 'side-navigation/permutations', + screenshotType: 'permutations', + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/slider.ts b/test/definitions/visual/slider.ts new file mode 100644 index 0000000000..49f7df5dfb --- /dev/null +++ b/test/definitions/visual/slider.ts @@ -0,0 +1,19 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'Slider', + componentName: 'slider', + tests: [ + { + description: 'permutations - standalone', + path: 'slider/permutations', + screenshotType: 'permutations', + configuration: { width: 800 }, + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/space-between.ts b/test/definitions/visual/space-between.ts new file mode 100644 index 0000000000..636d375d42 --- /dev/null +++ b/test/definitions/visual/space-between.ts @@ -0,0 +1,28 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'SpaceBetween', + componentName: 'space-between', + tests: [ + { + description: 'Permutations', + path: 'space-between/permutations', + screenshotType: 'permutations', + }, + { + description: 'in ColumnLayout and Grid', + path: 'space-between/nested-components', + screenshotType: 'screenshotArea', + }, + { + description: 'Alignment permutations', + path: 'space-between/alignment.permutations', + screenshotType: 'permutations', + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/spinner.ts b/test/definitions/visual/spinner.ts new file mode 100644 index 0000000000..65aa6c6ca1 --- /dev/null +++ b/test/definitions/visual/spinner.ts @@ -0,0 +1,23 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'Spinner', + componentName: 'spinner', + tests: [ + { + description: 'Alignment with text', + path: 'spinner/text-align', + screenshotType: 'screenshotArea', + }, + { + description: 'Permutations', + path: 'spinner/permutations', + screenshotType: 'permutations', + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/split-panel.ts b/test/definitions/visual/split-panel.ts new file mode 100644 index 0000000000..cfbca3b7a5 --- /dev/null +++ b/test/definitions/visual/split-panel.ts @@ -0,0 +1,93 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'Split panel', + componentName: 'split-panel', + tests: [ + { + description: 'position bottom', + path: 'app-layout/with-split-panel', + screenshotType: 'viewport', + setup: async ({ page }) => { + await page.click('aria/Open panel'); + }, + }, + { + description: 'position bottom - closed', + path: 'app-layout/with-split-panel', + screenshotType: 'viewport', + }, + { + description: 'position side', + path: 'app-layout/with-split-panel', + screenshotType: 'viewport', + setup: async ({ page }) => { + await page.click('aria/Open panel'); + await page.click('aria/Preferences'); + await page.click('aria/Side'); + await page.click('aria/Confirm'); + }, + }, + { + description: 'position side with tools open', + path: 'app-layout/with-split-panel', + screenshotType: 'viewport', + setup: async ({ page }) => { + await page.click('aria/Open panel'); + await page.click('aria/Preferences'); + await page.click('aria/Side'); + await page.click('aria/Confirm'); + await page.waitForVisible('aria/Open tools'); + await page.click('aria/Open tools'); + }, + }, + { + description: 'position side - closed', + path: 'app-layout/with-split-panel', + screenshotType: 'viewport', + setup: async ({ page }) => { + await page.click('aria/Open panel'); + await page.click('[aria-label="Preferences"]'); + await page.click('aria/Side'); + await page.click('aria/Confirm'); + await page.click('aria/Close panel'); + }, + }, + { + description: 'preferences open', + path: 'app-layout/with-split-panel', + screenshotType: 'viewport', + setup: async ({ page }) => { + await page.click('aria/Open panel'); + await page.click('aria/Preferences'); + }, + }, + { + description: 'popover in bottom panel', + path: 'app-layout/with-split-panel', + screenshotType: 'viewport', + setup: async ({ page, wrapper, browser }) => { + await page.click('aria/Open panel'); + await page.click(wrapper.findSplitPanel().findOpenPanelBottom().findPopover().findTrigger().toSelector()); + browser.$('[data-testid="scroll-me"]').scrollIntoView(); + }, + }, + { + description: 'headerBefore, info link, actions and description', + path: 'app-layout/split-panel-with-custom-header', + screenshotType: 'screenshotArea', + queryParams: { renderActionsButtonDropdown: 'true', renderBeforeBadge: 'true', renderInfoLink: 'true' }, + }, + { + description: 'Entire layout defined in headerBefore slot', + path: 'app-layout/split-panel-with-custom-header', + screenshotType: 'screenshotArea', + queryParams: { renderActionsButtonDropdown: 'true', renderBeforeButtons: 'true' }, + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/status-indicator.ts b/test/definitions/visual/status-indicator.ts new file mode 100644 index 0000000000..526849f4fa --- /dev/null +++ b/test/definitions/visual/status-indicator.ts @@ -0,0 +1,18 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'StatusIndicator', + componentName: 'status-indicator', + tests: [ + { + description: 'permutations', + path: 'status-indicator/permutations', + screenshotType: 'permutations', + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/steps.ts b/test/definitions/visual/steps.ts new file mode 100644 index 0000000000..3c21b870fb --- /dev/null +++ b/test/definitions/visual/steps.ts @@ -0,0 +1,18 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'Steps', + componentName: 'steps', + tests: [ + { + description: 'permutations', + path: 'steps/permutations', + screenshotType: 'permutations', + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/table-cells.ts b/test/definitions/visual/table-cells.ts new file mode 100644 index 0000000000..38ebde3b8e --- /dev/null +++ b/test/definitions/visual/table-cells.ts @@ -0,0 +1,20 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'Table cells', + componentName: 'table-cells', + tests: [ + { + description: 'vertical align', + path: 'table/cell-permutations', + screenshotType: 'screenshotArea', + configuration: { width: 1200 }, + queryParams: { verticalAlignTop: 'true' }, + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/table-embedded.ts b/test/definitions/visual/table-embedded.ts new file mode 100644 index 0000000000..06da54e843 --- /dev/null +++ b/test/definitions/visual/table-embedded.ts @@ -0,0 +1,23 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'Table embedded', + componentName: 'table-embedded', + tests: [ + { + description: 'in alert', + path: 'table/embedded-in-alert', + screenshotType: 'viewport', + }, + { + description: 'stacked and container variants', + path: 'table/stacked-and-container-variant', + screenshotType: 'viewport', + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/table-inline-editing.ts b/test/definitions/visual/table-inline-editing.ts new file mode 100644 index 0000000000..123df5b2f1 --- /dev/null +++ b/test/definitions/visual/table-inline-editing.ts @@ -0,0 +1,54 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'Table inline editing', + componentName: 'table-inline-editing', + tests: [ + { + description: 'permutations', + path: 'table/inline-editor.permutations', + screenshotType: 'permutations', + }, + { + description: 'active select editing', + path: 'table/editable', + screenshotType: 'screenshotArea', + setup: async ({ page }) => { + await page.click('[aria-label="Edit EKXAM4L45YPC8 TLS Version"]'); + }, + }, + { + description: 'active select editing with open dropdown', + path: 'table/editable', + screenshotType: 'screenshotArea', + setup: async ({ page, wrapper }) => { + await page.click('[aria-label="Edit EKXAM4L45YPC8 TLS Version"]'); + await page.click(wrapper.findSelect().findTrigger().toSelector()); + }, + }, + { + description: 'hovering over cell, resizableColumns=${resizableColumns}', + path: 'table/editable', + screenshotType: 'screenshotArea', + setup: async ({ page }) => { + await page.hoverElement('[aria-label="Edit EKXAM4L45YPC8 Domain name"]'); + }, + }, + { + description: 'active select editing with keyboard navigation', + path: 'table/editable', + screenshotType: 'screenshotArea', + configuration: { width: 1600 }, + queryParams: { enableKeyboardNavigation: 'true' }, + setup: async ({ page }) => { + await page.click('[data-testid="focus"]'); + await page.keys(['Tab', 'ArrowDown', 'ArrowRight', 'Enter']); + }, + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/table-resizable-columns.ts b/test/definitions/visual/table-resizable-columns.ts new file mode 100644 index 0000000000..7f373760d8 --- /dev/null +++ b/test/definitions/visual/table-resizable-columns.ts @@ -0,0 +1,69 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'Table', + componentName: 'table-resizable-columns', + tests: [ + { + description: 'resizable columns permutations', + path: 'table/resizable-columns-permutations', + screenshotType: 'permutations', + }, + { + description: 'focused column resizer', + path: 'table/resizable-columns', + screenshotType: 'screenshotArea', + setup: async ({ page }) => { + await page.buttonDownOnElement('#reset-state'); + await page.keys(['Tab']); + }, + }, + { + description: 'active column resizer on sticky header', + path: 'table/resizable-columns', + screenshotType: 'viewport', + setup: async ({ page, wrapper }) => { + const table = wrapper.findTable(); + await page.click('#sticky-header-toggle input'); + await page.windowScrollTo({ top: 600 }); + await page.buttonDownOnElement(table.findColumnResizer(3).toSelector()); + }, + }, + { + description: 'active column resizer', + path: 'table/resizable-columns', + screenshotType: 'screenshotArea', + setup: async ({ page, wrapper }) => { + const table = wrapper.findTable(); + await page.buttonDownOnElement(table.findColumnResizer(3).toSelector()); + }, + }, + { + description: 'pressed column resizer', + path: 'table/resizable-columns', + screenshotType: 'screenshotArea', + queryParams: { enableKeyboardNavigation: 'true' }, + setup: async ({ page, wrapper }) => { + const table = wrapper.findTable(); + await page.click(table.findHeaderSlot().toSelector()); + await page.keys(['Tab', 'ArrowRight', 'ArrowRight', 'ArrowRight', 'Enter']); + }, + }, + { + description: 'pressed last column resizer', + path: 'table/resizable-columns', + screenshotType: 'screenshotArea', + queryParams: { enableKeyboardNavigation: 'true' }, + setup: async ({ page, wrapper }) => { + const table = wrapper.findTable(); + await page.click(table.findHeaderSlot().toSelector()); + await page.keys(['Tab', 'ArrowRight', 'ArrowRight', 'ArrowRight', 'ArrowRight', 'Enter']); + }, + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/table-sticky-header.ts b/test/definitions/visual/table-sticky-header.ts new file mode 100644 index 0000000000..1f30619287 --- /dev/null +++ b/test/definitions/visual/table-sticky-header.ts @@ -0,0 +1,44 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'Table sticky header', + componentName: 'table-sticky-header', + tests: [ + { + description: 'initial state', + path: 'table/sticky-header', + screenshotType: 'viewport', + }, + { + description: 'mid-scroll sticky state - container variant', + path: 'table/sticky-header', + screenshotType: 'viewport', + setup: async ({ page }) => { + await page.click('#container'); + await page.windowScrollTo({ top: 400 }); + }, + }, + { + description: 'mid-scroll sticky state - embedded variant', + path: 'table/sticky-header', + screenshotType: 'viewport', + setup: async ({ page }) => { + await page.click('#embedded'); + await page.windowScrollTo({ top: 400 }); + }, + }, + { + description: 'bottom sticky state', + path: 'table/sticky-header', + screenshotType: 'viewport', + setup: async ({ page }) => { + await page.windowScrollTo({ top: 925 }); + }, + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/table-sticky-scrollbar.ts b/test/definitions/visual/table-sticky-scrollbar.ts new file mode 100644 index 0000000000..1f661f5a48 --- /dev/null +++ b/test/definitions/visual/table-sticky-scrollbar.ts @@ -0,0 +1,31 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'Table sticky scrollbar', + componentName: 'table-sticky-scrollbar', + tests: [ + { + description: 'on a plain page is positioned at the bottom', + path: 'table/sticky-scrollbar', + screenshotType: 'screenshotArea', + configuration: { width: 600, height: 800 }, + }, + { + description: 'on a page with app layout is positioned over the footer', + path: 'app-layout/with-table', + screenshotType: 'screenshotArea', + configuration: { width: 600, height: 800 }, + }, + { + description: 'on a page with app layout in a container is positioned over the bottom of the container', + path: 'app-layout/with-table-in-container', + screenshotType: 'screenshotArea', + configuration: { width: 600, height: 800 }, + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/table.ts b/test/definitions/visual/table.ts new file mode 100644 index 0000000000..15ed94bab1 --- /dev/null +++ b/test/definitions/visual/table.ts @@ -0,0 +1,130 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'Table', + componentName: 'table', + tests: [ + { + description: 'simple permutations at ${width}', + path: 'table/simple-permutations', + screenshotType: 'permutations', + }, + { + description: 'permutations at ${width}', + path: 'table/permutations', + screenshotType: 'permutations', + }, + { + description: 'expandable rows permutations', + path: 'table/expandable-rows.permutations', + screenshotType: 'permutations', + }, + { + description: 'empty state – default', + path: 'table/empty-state', + screenshotType: 'screenshotArea', + configuration: { width: 600 }, + }, + { + description: 'empty state – scrolled horizontally', + path: 'table/empty-state', + screenshotType: 'screenshotArea', + configuration: { width: 600 }, + setup: async ({ page }) => { + await page.click('#scroll-content'); + }, + }, + { + description: 'with features', + path: 'table/hooks', + screenshotType: 'screenshotArea', + }, + { + description: 'with striped rows', + path: 'table/striped-rows', + screenshotType: 'screenshotArea', + }, + { + description: 'inside stacked container', + path: 'table/sticky-header-in-stacked-container', + screenshotType: 'screenshotArea', + setup: async ({ page }) => { + await page.windowScrollTo({ top: 10 }); + await page.click('button=Actions'); + }, + }, + { + description: 'sticky header with open action button dropdown', + path: 'table/sticky-header-with-actions', + screenshotType: 'screenshotArea', + setup: async ({ page }) => { + await page.click('[data-test-id="actions-button"]'); + }, + }, + { + description: 'variants', + path: 'table/variants', + screenshotType: 'screenshotArea', + }, + { + description: 'focus on last cell inline action', + path: 'table/inline-actions', + screenshotType: 'screenshotArea', + setup: async ({ page, wrapper }) => { + const tableWrapper = wrapper.findTable('[data-testid="table-with-dropdown-actions"]'); + await page.click(tableWrapper.findRows().get(1).findButtonDropdown().findNativeButton().toSelector()); + await page.keys(['Escape']); + }, + }, + { + description: 'focus on first cell link', + path: 'table/inline-actions', + screenshotType: 'screenshotArea', + setup: async ({ page, wrapper }) => { + const tableWrapper = wrapper.findTable('[data-testid="table-with-dropdown-actions"]'); + await page.click(tableWrapper.findRowSelectionArea(1).toSelector()); + await page.keys(['Tab']); + }, + }, + { + description: 'first column sticky state', + path: 'table/sticky-columns', + screenshotType: 'screenshotArea', + configuration: { width: 800 }, + queryParams: { stickyColumnsFirst: '1' }, + }, + { + description: 'first column sticky state and selection', + path: 'table/sticky-columns', + screenshotType: 'screenshotArea', + configuration: { width: 800 }, + queryParams: { stickyColumnsFirst: '1', selectionType: 'single' }, + }, + { + description: 'first column sticky state and striped rows', + path: 'table/sticky-columns', + screenshotType: 'screenshotArea', + configuration: { width: 800 }, + queryParams: { stickyColumnsFirst: '1', stripedRows: 'true' }, + }, + { + description: 'first two columns sticky state', + path: 'table/sticky-columns', + screenshotType: 'screenshotArea', + configuration: { width: 800 }, + queryParams: { stickyColumnsFirst: '2' }, + }, + { + description: 'last column sticky state', + path: 'table/sticky-columns', + screenshotType: 'screenshotArea', + configuration: { width: 800 }, + queryParams: { stickyColumnsLast: '1' }, + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/tabs.ts b/test/definitions/visual/tabs.ts new file mode 100644 index 0000000000..5f7dceb628 --- /dev/null +++ b/test/definitions/visual/tabs.ts @@ -0,0 +1,80 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'Tabs', + componentName: 'tabs', + tests: [ + { + description: 'Permutations', + path: 'tabs/permutations', + screenshotType: 'permutations', + }, + { + description: 'Responsive permutations', + path: 'tabs/responsive-permutations', + screenshotType: 'screenshotArea', + }, + { + description: 'focuses next tab header after clicking on tab header without an href', + path: 'tabs/integration-test', + screenshotType: 'screenshotArea', + setup: async ({ page }) => { + await page.click('#first-tabs li:nth-child(3) button'); + await page.keys('ArrowRight'); + }, + }, + { + description: 'layout at ${width}px', + path: 'tabs/integration-test', + screenshotType: 'screenshotArea', + }, + { + description: 'focus active tab - default variant', + path: 'tabs/integration-test', + screenshotType: 'screenshotArea', + setup: async ({ page }) => { + await page.click('#click-this'); + await page.focusNextElement(); + }, + }, + { + description: 'focus active tab - container variant', + path: 'tabs/integration-test', + screenshotType: 'screenshotArea', + setup: async ({ page }) => { + await page.click('#click-this-2'); + await page.focusNextElement(); + }, + }, + { + description: 'focus content - default variant', + path: 'tabs/integration-test', + screenshotType: 'screenshotArea', + setup: async ({ page }) => { + await page.click('#click-this'); + await page.focusNextElement(); + await page.focusNextElement(); + }, + }, + { + description: 'focus content - container variant', + path: 'tabs/integration-test', + screenshotType: 'screenshotArea', + setup: async ({ page }) => { + await page.click('#click-this-2'); + await page.focusNextElement(); + await page.focusNextElement(); + }, + }, + { + description: 'Style Permutations', + path: 'tabs/style-permutations', + screenshotType: 'permutations', + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/tag-editor.ts b/test/definitions/visual/tag-editor.ts new file mode 100644 index 0000000000..041fdbef6a --- /dev/null +++ b/test/definitions/visual/tag-editor.ts @@ -0,0 +1,18 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'TagEditor', + componentName: 'tag-editor', + tests: [ + { + description: 'Permutations', + path: 'tag-editor/permutations', + screenshotType: 'permutations', + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/text-content.ts b/test/definitions/visual/text-content.ts new file mode 100644 index 0000000000..29b72be343 --- /dev/null +++ b/test/definitions/visual/text-content.ts @@ -0,0 +1,33 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'TextContainer', + componentName: 'text-content', + tests: [ + { + description: 'color property', + path: 'text-content/permutations', + screenshotType: 'screenshotArea', + }, + { + description: 'with nested Link components', + path: 'text-content/link-nesting', + screenshotType: 'screenshotArea', + }, + { + description: 'with nested Box components', + path: 'text-content/box-nesting', + screenshotType: 'screenshotArea', + }, + { + description: 'with icons in content', + path: 'text-content/iconography', + screenshotType: 'screenshotArea', + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/text-filter.ts b/test/definitions/visual/text-filter.ts new file mode 100644 index 0000000000..f291e70574 --- /dev/null +++ b/test/definitions/visual/text-filter.ts @@ -0,0 +1,18 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'TextFilter', + componentName: 'text-filter', + tests: [ + { + description: 'permutations', + path: 'text-filter/permutations', + screenshotType: 'permutations', + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/textarea.ts b/test/definitions/visual/textarea.ts new file mode 100644 index 0000000000..c497230b61 --- /dev/null +++ b/test/definitions/visual/textarea.ts @@ -0,0 +1,77 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const testStates = [ + { toggle: 'toggle-invalid', label: 'invalid', isInteractive: true }, + { toggle: 'toggle-disabled', label: 'disabled', isInteractive: false }, + { toggle: 'toggle-readonly', label: 'readonly', isInteractive: true }, + { toggle: 'toggle-warning', label: 'warning', isInteractive: true }, +]; + +function pseudoSelectorTests(withStyling: boolean): TestSuite { + return { + description: withStyling ? 'Pseudo Selectors with Custom Styling' : 'Pseudo Selectors', + tests: testStates.flatMap(state => [ + { + description: `${state.label} - focus`, + path: 'textarea/pseudo-selectors', + screenshotType: 'screenshotArea' as const, + setup: async ({ page, wrapper }) => { + const textareaSelector = wrapper + .findTextarea('[data-testid="test-textarea"]') + .findNativeTextarea() + .toSelector(); + if (withStyling) { + await page.click('#toggle-styling'); + } + await page.click(`#${state.toggle}`); + if (state.isInteractive) { + await page.click(textareaSelector); + } + }, + }, + { + description: `${state.label} - focus + hover`, + path: 'textarea/pseudo-selectors', + screenshotType: 'screenshotArea' as const, + setup: async ({ page, wrapper }) => { + const textareaSelector = wrapper + .findTextarea('[data-testid="test-textarea"]') + .findNativeTextarea() + .toSelector(); + if (withStyling) { + await page.click('#toggle-styling'); + } + await page.click(`#${state.toggle}`); + if (state.isInteractive) { + await page.click(textareaSelector); + } + await page.hoverElement(textareaSelector); + }, + }, + ]), + }; +} + +const suite: TestSuite = { + description: 'Textarea', + componentName: 'textarea', + tests: [ + { + description: 'Permutations', + path: 'textarea/permutations', + screenshotType: 'permutations', + }, + { + description: 'Style Permutations', + path: 'textarea/style-permutations', + screenshotType: 'permutations', + }, + pseudoSelectorTests(false), + pseudoSelectorTests(true), + ], +}; + +export default suite; diff --git a/test/definitions/visual/tiles.ts b/test/definitions/visual/tiles.ts new file mode 100644 index 0000000000..51c290fc80 --- /dev/null +++ b/test/definitions/visual/tiles.ts @@ -0,0 +1,23 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'Tiles', + componentName: 'tiles', + tests: [ + { + description: 'tiles at "${breakpoint}"', + path: 'tiles/simple', + screenshotType: 'screenshotArea', + }, + { + description: 'permutations at "${breakpoint}"', + path: 'tiles/permutations', + screenshotType: 'permutations', + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/time-input.ts b/test/definitions/visual/time-input.ts new file mode 100644 index 0000000000..b2e6fc2dcc --- /dev/null +++ b/test/definitions/visual/time-input.ts @@ -0,0 +1,18 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'Time Input', + componentName: 'time-input', + tests: [ + { + description: 'Permutations', + path: 'time-input/permutations', + screenshotType: 'permutations', + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/toggle-button.ts b/test/definitions/visual/toggle-button.ts new file mode 100644 index 0000000000..c7b55e8079 --- /dev/null +++ b/test/definitions/visual/toggle-button.ts @@ -0,0 +1,26 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'Toggle button', + componentName: 'toggle-button', + tests: [ + { + description: 'permutations', + path: 'toggle-button/permutations', + screenshotType: 'permutations', + }, + { + description: 'hovering over normal variant', + path: 'toggle-button/permutations', + screenshotType: 'permutations', + setup: async ({ page }) => { + await page.hoverElement('[aria-label="Favorite"][aria-pressed="false"]'); + }, + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/toggle.ts b/test/definitions/visual/toggle.ts new file mode 100644 index 0000000000..f2e3bd0cd1 --- /dev/null +++ b/test/definitions/visual/toggle.ts @@ -0,0 +1,37 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'Toggle', + componentName: 'toggle', + tests: [ + { + description: 'Permutations', + path: 'toggle/permutations', + screenshotType: 'permutations', + }, + { + description: 'Toggle is focused', + path: 'toggle/focus-test', + screenshotType: 'screenshotArea', + setup: async ({ page }) => { + await page.click('#focus-target'); + await page.focusNextElement(); + }, + }, + { + description: 'Toggle has label with a correct width', + path: 'toggle/labels-highlight', + screenshotType: 'screenshotArea', + }, + { + description: 'Style custom page', + path: 'toggle/style-custom', + screenshotType: 'screenshotArea', + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/token-group.ts b/test/definitions/visual/token-group.ts new file mode 100644 index 0000000000..99ac6b49e6 --- /dev/null +++ b/test/definitions/visual/token-group.ts @@ -0,0 +1,23 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'TokenGroup', + componentName: 'token-group', + tests: [ + { + description: 'Permutations', + path: 'token-group/permutations', + screenshotType: 'permutations', + }, + { + description: 'Simple', + path: 'token-group/index', + screenshotType: 'screenshotArea', + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/top-navigation.ts b/test/definitions/visual/top-navigation.ts new file mode 100644 index 0000000000..d21c71c1fb --- /dev/null +++ b/test/definitions/visual/top-navigation.ts @@ -0,0 +1,54 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'Top navigation', + componentName: 'top-navigation', + tests: [ + { + description: 'Responsiveness', + path: 'top-navigation/screenshot', + screenshotType: 'screenshotArea', + configuration: { width: 1300 }, + }, + { + description: 'Dropdown menu utility', + path: 'top-navigation/scenario-full-page', + screenshotType: 'viewport', + configuration: { width: 1300, height: 800 }, + setup: async ({ page, wrapper }) => { + await page.click(wrapper.findTopNavigation().findUtility(4).toSelector()); + }, + }, + { + description: 'Utility permutations', + path: 'top-navigation/utility.permutations', + screenshotType: 'permutations', + }, + { + description: 'Overflow menu - outer', + path: 'top-navigation/scenario-full-page', + screenshotType: 'viewport', + configuration: { width: 500, height: 800 }, + setup: async ({ page, wrapper }) => { + await page.click(wrapper.findTopNavigation().findOverflowMenuButton().toSelector()); + await page.keys(['Tab']); + }, + }, + { + description: 'Overflow menu - dropdown', + path: 'top-navigation/scenario-full-page', + screenshotType: 'viewport', + configuration: { width: 500, height: 800 }, + setup: async ({ page, wrapper }) => { + await page.click(wrapper.findTopNavigation().findOverflowMenuButton().toSelector()); + await page.click(wrapper.findTopNavigation().findOverflowMenu().findUtility(3).toSelector()); + await page.keys(['Tab']); + }, + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/tree-view.ts b/test/definitions/visual/tree-view.ts new file mode 100644 index 0000000000..4809c79fa2 --- /dev/null +++ b/test/definitions/visual/tree-view.ts @@ -0,0 +1,28 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'Tree View', + componentName: 'tree-view', + tests: [ + { + description: 'basic', + path: 'tree-view/basic', + screenshotType: 'screenshotArea', + }, + { + description: 'with different toggle icon', + path: 'tree-view/basic', + screenshotType: 'screenshotArea', + setup: async ({ page, wrapper }) => { + const select = wrapper.findSelect(); + await page.click(select.findTrigger().toSelector()); + await page.click(select.findDropdown().findOptionByValue('custom').toSelector()); + }, + }, + ], +}; + +export default suite; diff --git a/test/definitions/visual/wizard.ts b/test/definitions/visual/wizard.ts new file mode 100644 index 0000000000..51864a6396 --- /dev/null +++ b/test/definitions/visual/wizard.ts @@ -0,0 +1,42 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { TestSuite } from '../types'; + +const suite: TestSuite = { + description: 'Wizard', + componentName: 'wizard', + tests: [ + ...[600, 1280].map(width => ({ + description: `width ${width}px`, + tests: [ + { + description: 'first step', + path: 'wizard/wizard-screenshot', + screenshotType: 'screenshotArea' as const, + configuration: { width }, + }, + { + description: 'second step', + path: 'wizard/wizard-screenshot', + screenshotType: 'screenshotArea' as const, + configuration: { width }, + setup: async ({ page }: { page: any }) => { + await page.click('#next'); + }, + }, + ], + })), + { + description: 'steps menu expanded in mobile view', + path: 'wizard/wizard-screenshot', + screenshotType: 'screenshotArea', + configuration: { width: 600 }, + setup: async ({ page }) => { + await page.click('[role="button"][aria-expanded]'); + }, + }, + ], +}; + +export default suite; diff --git a/test/visual/action-card.test.ts b/test/visual/action-card.test.ts new file mode 100644 index 0000000000..24908af18c --- /dev/null +++ b/test/visual/action-card.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/action-card'; + +runTestSuites([suite]); diff --git a/test/visual/alert.test.ts b/test/visual/alert.test.ts new file mode 100644 index 0000000000..868c55ff1d --- /dev/null +++ b/test/visual/alert.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/alert'; + +runTestSuites([suite]); diff --git a/test/visual/app-layout-content-paddings.test.ts b/test/visual/app-layout-content-paddings.test.ts new file mode 100644 index 0000000000..e566d79817 --- /dev/null +++ b/test/visual/app-layout-content-paddings.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/app-layout-content-paddings'; + +runTestSuites([suite]); diff --git a/test/visual/app-layout-drawers.test.ts b/test/visual/app-layout-drawers.test.ts new file mode 100644 index 0000000000..c66454010d --- /dev/null +++ b/test/visual/app-layout-drawers.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/app-layout-drawers'; + +runTestSuites([suite]); diff --git a/test/visual/app-layout-flashbar.test.ts b/test/visual/app-layout-flashbar.test.ts new file mode 100644 index 0000000000..333642e5f3 --- /dev/null +++ b/test/visual/app-layout-flashbar.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/app-layout-flashbar'; + +runTestSuites([suite]); diff --git a/test/visual/app-layout-header.test.ts b/test/visual/app-layout-header.test.ts new file mode 100644 index 0000000000..682f71ffe2 --- /dev/null +++ b/test/visual/app-layout-header.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/app-layout-header'; + +runTestSuites([suite]); diff --git a/test/visual/app-layout-multi.test.ts b/test/visual/app-layout-multi.test.ts new file mode 100644 index 0000000000..244019c8fb --- /dev/null +++ b/test/visual/app-layout-multi.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/app-layout-multi'; + +runTestSuites([suite]); diff --git a/test/visual/app-layout-responsive-1280.test.ts b/test/visual/app-layout-responsive-1280.test.ts new file mode 100644 index 0000000000..0324b2bf39 --- /dev/null +++ b/test/visual/app-layout-responsive-1280.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/app-layout-responsive-1280'; + +runTestSuites([suite]); diff --git a/test/visual/app-layout-responsive-1400.test.ts b/test/visual/app-layout-responsive-1400.test.ts new file mode 100644 index 0000000000..745372c34e --- /dev/null +++ b/test/visual/app-layout-responsive-1400.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/app-layout-responsive-1400'; + +runTestSuites([suite]); diff --git a/test/visual/app-layout-responsive-1920.test.ts b/test/visual/app-layout-responsive-1920.test.ts new file mode 100644 index 0000000000..bee5fc8763 --- /dev/null +++ b/test/visual/app-layout-responsive-1920.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/app-layout-responsive-1920'; + +runTestSuites([suite]); diff --git a/test/visual/app-layout-responsive-2540.test.ts b/test/visual/app-layout-responsive-2540.test.ts new file mode 100644 index 0000000000..48bc8580da --- /dev/null +++ b/test/visual/app-layout-responsive-2540.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/app-layout-responsive-2540'; + +runTestSuites([suite]); diff --git a/test/visual/app-layout-responsive-600.test.ts b/test/visual/app-layout-responsive-600.test.ts new file mode 100644 index 0000000000..cd9243cb32 --- /dev/null +++ b/test/visual/app-layout-responsive-600.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/app-layout-responsive-600'; + +runTestSuites([suite]); diff --git a/test/visual/app-layout-sticky-table-header-split-panel.test.ts b/test/visual/app-layout-sticky-table-header-split-panel.test.ts new file mode 100644 index 0000000000..c1ad3016a1 --- /dev/null +++ b/test/visual/app-layout-sticky-table-header-split-panel.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/app-layout-sticky-table-header-split-panel'; + +runTestSuites([suite]); diff --git a/test/visual/app-layout-toolbar.test.ts b/test/visual/app-layout-toolbar.test.ts new file mode 100644 index 0000000000..398d6386f8 --- /dev/null +++ b/test/visual/app-layout-toolbar.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/app-layout-toolbar'; + +runTestSuites([suite]); diff --git a/test/visual/app-layout-z-index.test.ts b/test/visual/app-layout-z-index.test.ts new file mode 100644 index 0000000000..5f69f77b71 --- /dev/null +++ b/test/visual/app-layout-z-index.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/app-layout-z-index'; + +runTestSuites([suite]); diff --git a/test/visual/app-layout.test.ts b/test/visual/app-layout.test.ts new file mode 100644 index 0000000000..21c3a6ce25 --- /dev/null +++ b/test/visual/app-layout.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/app-layout'; + +runTestSuites([suite]); diff --git a/test/visual/area-chart.test.ts b/test/visual/area-chart.test.ts new file mode 100644 index 0000000000..4ffc4e042e --- /dev/null +++ b/test/visual/area-chart.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/area-chart'; + +runTestSuites([suite]); diff --git a/test/visual/attribute-editor.test.ts b/test/visual/attribute-editor.test.ts new file mode 100644 index 0000000000..6a57853125 --- /dev/null +++ b/test/visual/attribute-editor.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/attribute-editor'; + +runTestSuites([suite]); diff --git a/test/visual/autosuggest.test.ts b/test/visual/autosuggest.test.ts new file mode 100644 index 0000000000..d88cad7117 --- /dev/null +++ b/test/visual/autosuggest.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/autosuggest'; + +runTestSuites([suite]); diff --git a/test/visual/badge.test.ts b/test/visual/badge.test.ts new file mode 100644 index 0000000000..1163052443 --- /dev/null +++ b/test/visual/badge.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/badge'; + +runTestSuites([suite]); diff --git a/test/visual/bar-chart.test.ts b/test/visual/bar-chart.test.ts new file mode 100644 index 0000000000..d54245d935 --- /dev/null +++ b/test/visual/bar-chart.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/bar-chart'; + +runTestSuites([suite]); diff --git a/test/visual/box.test.ts b/test/visual/box.test.ts new file mode 100644 index 0000000000..9422b04f64 --- /dev/null +++ b/test/visual/box.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/box'; + +runTestSuites([suite]); diff --git a/test/visual/breadcrumb-group.test.ts b/test/visual/breadcrumb-group.test.ts new file mode 100644 index 0000000000..77450f3700 --- /dev/null +++ b/test/visual/breadcrumb-group.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/breadcrumb-group'; + +runTestSuites([suite]); diff --git a/test/visual/button-dropdown.test.ts b/test/visual/button-dropdown.test.ts new file mode 100644 index 0000000000..16b90ff4da --- /dev/null +++ b/test/visual/button-dropdown.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/button-dropdown'; + +runTestSuites([suite]); diff --git a/test/visual/button-group.test.ts b/test/visual/button-group.test.ts new file mode 100644 index 0000000000..100c7f9508 --- /dev/null +++ b/test/visual/button-group.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/button-group'; + +runTestSuites([suite]); diff --git a/test/visual/button.test.ts b/test/visual/button.test.ts new file mode 100644 index 0000000000..d4b642af53 --- /dev/null +++ b/test/visual/button.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/button'; + +runTestSuites([suite]); diff --git a/test/visual/cards.test.ts b/test/visual/cards.test.ts new file mode 100644 index 0000000000..ecb282b266 --- /dev/null +++ b/test/visual/cards.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/cards'; + +runTestSuites([suite]); diff --git a/test/visual/checkbox.test.ts b/test/visual/checkbox.test.ts new file mode 100644 index 0000000000..f569e2e7ab --- /dev/null +++ b/test/visual/checkbox.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/checkbox'; + +runTestSuites([suite]); diff --git a/test/visual/code-editor.test.ts b/test/visual/code-editor.test.ts new file mode 100644 index 0000000000..735638ea5d --- /dev/null +++ b/test/visual/code-editor.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/code-editor'; + +runTestSuites([suite]); diff --git a/test/visual/collection-preferences.test.ts b/test/visual/collection-preferences.test.ts new file mode 100644 index 0000000000..ac54029622 --- /dev/null +++ b/test/visual/collection-preferences.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/collection-preferences'; + +runTestSuites([suite]); diff --git a/test/visual/column-layout.test.ts b/test/visual/column-layout.test.ts new file mode 100644 index 0000000000..55749a8e8b --- /dev/null +++ b/test/visual/column-layout.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/column-layout'; + +runTestSuites([suite]); diff --git a/test/visual/container-sticky.test.ts b/test/visual/container-sticky.test.ts new file mode 100644 index 0000000000..ce014d9805 --- /dev/null +++ b/test/visual/container-sticky.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/container-sticky'; + +runTestSuites([suite]); diff --git a/test/visual/container.test.ts b/test/visual/container.test.ts new file mode 100644 index 0000000000..d738bd8429 --- /dev/null +++ b/test/visual/container.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/container'; + +runTestSuites([suite]); diff --git a/test/visual/content-layout-permutations.test.ts b/test/visual/content-layout-permutations.test.ts new file mode 100644 index 0000000000..20de7543dc --- /dev/null +++ b/test/visual/content-layout-permutations.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/content-layout-permutations'; + +runTestSuites([suite]); diff --git a/test/visual/content-layout.test.ts b/test/visual/content-layout.test.ts new file mode 100644 index 0000000000..cc62ebf2a4 --- /dev/null +++ b/test/visual/content-layout.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/content-layout'; + +runTestSuites([suite]); diff --git a/test/visual/copy-to-clipboard.test.ts b/test/visual/copy-to-clipboard.test.ts new file mode 100644 index 0000000000..8f6f3afa5a --- /dev/null +++ b/test/visual/copy-to-clipboard.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/copy-to-clipboard'; + +runTestSuites([suite]); diff --git a/test/visual/date-input.test.ts b/test/visual/date-input.test.ts new file mode 100644 index 0000000000..d711364611 --- /dev/null +++ b/test/visual/date-input.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/date-input'; + +runTestSuites([suite]); diff --git a/test/visual/date-picker.test.ts b/test/visual/date-picker.test.ts new file mode 100644 index 0000000000..fd7087585b --- /dev/null +++ b/test/visual/date-picker.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/date-picker'; + +runTestSuites([suite]); diff --git a/test/visual/date-range-picker.test.ts b/test/visual/date-range-picker.test.ts new file mode 100644 index 0000000000..df5ed2d355 --- /dev/null +++ b/test/visual/date-range-picker.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/date-range-picker'; + +runTestSuites([suite]); diff --git a/test/visual/divider.test.ts b/test/visual/divider.test.ts new file mode 100644 index 0000000000..30305f9eff --- /dev/null +++ b/test/visual/divider.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/divider'; + +runTestSuites([suite]); diff --git a/test/visual/drawer.test.ts b/test/visual/drawer.test.ts new file mode 100644 index 0000000000..0a16626101 --- /dev/null +++ b/test/visual/drawer.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/drawer'; + +runTestSuites([suite]); diff --git a/test/visual/dropdown.test.ts b/test/visual/dropdown.test.ts new file mode 100644 index 0000000000..1dbb5ca9b2 --- /dev/null +++ b/test/visual/dropdown.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/dropdown'; + +runTestSuites([suite]); diff --git a/test/visual/expandable-section.test.ts b/test/visual/expandable-section.test.ts new file mode 100644 index 0000000000..b052d5cf5f --- /dev/null +++ b/test/visual/expandable-section.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/expandable-section'; + +runTestSuites([suite]); diff --git a/test/visual/file-dropzone.test.ts b/test/visual/file-dropzone.test.ts new file mode 100644 index 0000000000..ad937625a3 --- /dev/null +++ b/test/visual/file-dropzone.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/file-dropzone'; + +runTestSuites([suite]); diff --git a/test/visual/file-input.test.ts b/test/visual/file-input.test.ts new file mode 100644 index 0000000000..918feeb9ff --- /dev/null +++ b/test/visual/file-input.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/file-input'; + +runTestSuites([suite]); diff --git a/test/visual/file-token-group.test.ts b/test/visual/file-token-group.test.ts new file mode 100644 index 0000000000..96b0e7396b --- /dev/null +++ b/test/visual/file-token-group.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/file-token-group'; + +runTestSuites([suite]); diff --git a/test/visual/file-upload.test.ts b/test/visual/file-upload.test.ts new file mode 100644 index 0000000000..06dafb87ca --- /dev/null +++ b/test/visual/file-upload.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/file-upload'; + +runTestSuites([suite]); diff --git a/test/visual/flashbar-stacked.test.ts b/test/visual/flashbar-stacked.test.ts new file mode 100644 index 0000000000..5e37f288af --- /dev/null +++ b/test/visual/flashbar-stacked.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/flashbar-stacked'; + +runTestSuites([suite]); diff --git a/test/visual/flashbar.test.ts b/test/visual/flashbar.test.ts new file mode 100644 index 0000000000..d02aaae84c --- /dev/null +++ b/test/visual/flashbar.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/flashbar'; + +runTestSuites([suite]); diff --git a/test/visual/form-field.test.ts b/test/visual/form-field.test.ts new file mode 100644 index 0000000000..8406e9351b --- /dev/null +++ b/test/visual/form-field.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/form-field'; + +runTestSuites([suite]); diff --git a/test/visual/form.test.ts b/test/visual/form.test.ts new file mode 100644 index 0000000000..89a44f2ec8 --- /dev/null +++ b/test/visual/form.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/form'; + +runTestSuites([suite]); diff --git a/test/visual/grid.test.ts b/test/visual/grid.test.ts new file mode 100644 index 0000000000..28313ba4f2 --- /dev/null +++ b/test/visual/grid.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/grid'; + +runTestSuites([suite]); diff --git a/test/visual/header.test.ts b/test/visual/header.test.ts new file mode 100644 index 0000000000..c08e211517 --- /dev/null +++ b/test/visual/header.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/header'; + +runTestSuites([suite]); diff --git a/test/visual/help-panel.test.ts b/test/visual/help-panel.test.ts new file mode 100644 index 0000000000..10fe7ed091 --- /dev/null +++ b/test/visual/help-panel.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/help-panel'; + +runTestSuites([suite]); diff --git a/test/visual/icon.test.ts b/test/visual/icon.test.ts new file mode 100644 index 0000000000..ecd9f9656a --- /dev/null +++ b/test/visual/icon.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/icon'; + +runTestSuites([suite]); diff --git a/test/visual/input.test.ts b/test/visual/input.test.ts new file mode 100644 index 0000000000..361de80dd5 --- /dev/null +++ b/test/visual/input.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/input'; + +runTestSuites([suite]); diff --git a/test/visual/item-card.test.ts b/test/visual/item-card.test.ts new file mode 100644 index 0000000000..1c06f6493b --- /dev/null +++ b/test/visual/item-card.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/item-card'; + +runTestSuites([suite]); diff --git a/test/visual/key-value-pairs.test.ts b/test/visual/key-value-pairs.test.ts new file mode 100644 index 0000000000..7702a5645b --- /dev/null +++ b/test/visual/key-value-pairs.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/key-value-pairs'; + +runTestSuites([suite]); diff --git a/test/visual/line-chart.test.ts b/test/visual/line-chart.test.ts new file mode 100644 index 0000000000..d6d088adf9 --- /dev/null +++ b/test/visual/line-chart.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/line-chart'; + +runTestSuites([suite]); diff --git a/test/visual/link.test.ts b/test/visual/link.test.ts new file mode 100644 index 0000000000..bd34346c9f --- /dev/null +++ b/test/visual/link.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/link'; + +runTestSuites([suite]); diff --git a/test/visual/list.test.ts b/test/visual/list.test.ts new file mode 100644 index 0000000000..aae3228105 --- /dev/null +++ b/test/visual/list.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/list'; + +runTestSuites([suite]); diff --git a/test/visual/mixed-line-bar-chart.test.ts b/test/visual/mixed-line-bar-chart.test.ts new file mode 100644 index 0000000000..0409acf8a6 --- /dev/null +++ b/test/visual/mixed-line-bar-chart.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/mixed-line-bar-chart'; + +runTestSuites([suite]); diff --git a/test/visual/modal.test.ts b/test/visual/modal.test.ts new file mode 100644 index 0000000000..ad2c71ea48 --- /dev/null +++ b/test/visual/modal.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/modal'; + +runTestSuites([suite]); diff --git a/test/visual/multiselect.test.ts b/test/visual/multiselect.test.ts new file mode 100644 index 0000000000..632ad5afaa --- /dev/null +++ b/test/visual/multiselect.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/multiselect'; + +runTestSuites([suite]); diff --git a/test/visual/pagination.test.ts b/test/visual/pagination.test.ts new file mode 100644 index 0000000000..0a868faa5d --- /dev/null +++ b/test/visual/pagination.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/pagination'; + +runTestSuites([suite]); diff --git a/test/visual/pie-chart.test.ts b/test/visual/pie-chart.test.ts new file mode 100644 index 0000000000..31d111a8db --- /dev/null +++ b/test/visual/pie-chart.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/pie-chart'; + +runTestSuites([suite]); diff --git a/test/visual/popover.test.ts b/test/visual/popover.test.ts new file mode 100644 index 0000000000..1573aa33d1 --- /dev/null +++ b/test/visual/popover.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/popover'; + +runTestSuites([suite]); diff --git a/test/visual/progress-bar.test.ts b/test/visual/progress-bar.test.ts new file mode 100644 index 0000000000..8bbd40ad30 --- /dev/null +++ b/test/visual/progress-bar.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/progress-bar'; + +runTestSuites([suite]); diff --git a/test/visual/prompt-input.test.ts b/test/visual/prompt-input.test.ts new file mode 100644 index 0000000000..c8dbcac0b4 --- /dev/null +++ b/test/visual/prompt-input.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/prompt-input'; + +runTestSuites([suite]); diff --git a/test/visual/property-filter.test.ts b/test/visual/property-filter.test.ts new file mode 100644 index 0000000000..d7290f1142 --- /dev/null +++ b/test/visual/property-filter.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/property-filter'; + +runTestSuites([suite]); diff --git a/test/visual/radio-button.test.ts b/test/visual/radio-button.test.ts new file mode 100644 index 0000000000..527390dcf0 --- /dev/null +++ b/test/visual/radio-button.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/radio-button'; + +runTestSuites([suite]); diff --git a/test/visual/radio-group.test.ts b/test/visual/radio-group.test.ts new file mode 100644 index 0000000000..b267dc05e3 --- /dev/null +++ b/test/visual/radio-group.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/radio-group'; + +runTestSuites([suite]); diff --git a/test/visual/s3-resource-selector.test.ts b/test/visual/s3-resource-selector.test.ts new file mode 100644 index 0000000000..f38b1750cc --- /dev/null +++ b/test/visual/s3-resource-selector.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/s3-resource-selector'; + +runTestSuites([suite]); diff --git a/test/visual/segmented-control.test.ts b/test/visual/segmented-control.test.ts new file mode 100644 index 0000000000..d96906c91d --- /dev/null +++ b/test/visual/segmented-control.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/segmented-control'; + +runTestSuites([suite]); diff --git a/test/visual/select.test.ts b/test/visual/select.test.ts new file mode 100644 index 0000000000..d3adc1dc91 --- /dev/null +++ b/test/visual/select.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/select'; + +runTestSuites([suite]); diff --git a/test/visual/side-navigation.test.ts b/test/visual/side-navigation.test.ts new file mode 100644 index 0000000000..91aa6d4895 --- /dev/null +++ b/test/visual/side-navigation.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/side-navigation'; + +runTestSuites([suite]); diff --git a/test/visual/slider.test.ts b/test/visual/slider.test.ts new file mode 100644 index 0000000000..ea85f9c860 --- /dev/null +++ b/test/visual/slider.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/slider'; + +runTestSuites([suite]); diff --git a/test/visual/space-between.test.ts b/test/visual/space-between.test.ts new file mode 100644 index 0000000000..4afe1219bc --- /dev/null +++ b/test/visual/space-between.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/space-between'; + +runTestSuites([suite]); diff --git a/test/visual/spinner.test.ts b/test/visual/spinner.test.ts new file mode 100644 index 0000000000..38e1ede756 --- /dev/null +++ b/test/visual/spinner.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/spinner'; + +runTestSuites([suite]); diff --git a/test/visual/split-panel.test.ts b/test/visual/split-panel.test.ts new file mode 100644 index 0000000000..c9268d3c3a --- /dev/null +++ b/test/visual/split-panel.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/split-panel'; + +runTestSuites([suite]); diff --git a/test/visual/status-indicator.test.ts b/test/visual/status-indicator.test.ts new file mode 100644 index 0000000000..88e5d5942d --- /dev/null +++ b/test/visual/status-indicator.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/status-indicator'; + +runTestSuites([suite]); diff --git a/test/visual/steps.test.ts b/test/visual/steps.test.ts new file mode 100644 index 0000000000..c82db29656 --- /dev/null +++ b/test/visual/steps.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/steps'; + +runTestSuites([suite]); diff --git a/test/visual/table-cells.test.ts b/test/visual/table-cells.test.ts new file mode 100644 index 0000000000..31e495ea22 --- /dev/null +++ b/test/visual/table-cells.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/table-cells'; + +runTestSuites([suite]); diff --git a/test/visual/table-embedded.test.ts b/test/visual/table-embedded.test.ts new file mode 100644 index 0000000000..e158981079 --- /dev/null +++ b/test/visual/table-embedded.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/table-embedded'; + +runTestSuites([suite]); diff --git a/test/visual/table-inline-editing.test.ts b/test/visual/table-inline-editing.test.ts new file mode 100644 index 0000000000..d6321b5b38 --- /dev/null +++ b/test/visual/table-inline-editing.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/table-inline-editing'; + +runTestSuites([suite]); diff --git a/test/visual/table-resizable-columns.test.ts b/test/visual/table-resizable-columns.test.ts new file mode 100644 index 0000000000..bb0a535139 --- /dev/null +++ b/test/visual/table-resizable-columns.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/table-resizable-columns'; + +runTestSuites([suite]); diff --git a/test/visual/table-sticky-header.test.ts b/test/visual/table-sticky-header.test.ts new file mode 100644 index 0000000000..68a994750e --- /dev/null +++ b/test/visual/table-sticky-header.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/table-sticky-header'; + +runTestSuites([suite]); diff --git a/test/visual/table-sticky-scrollbar.test.ts b/test/visual/table-sticky-scrollbar.test.ts new file mode 100644 index 0000000000..2ac31ef9b9 --- /dev/null +++ b/test/visual/table-sticky-scrollbar.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/table-sticky-scrollbar'; + +runTestSuites([suite]); diff --git a/test/visual/table.test.ts b/test/visual/table.test.ts new file mode 100644 index 0000000000..2b2bc6a6d9 --- /dev/null +++ b/test/visual/table.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/table'; + +runTestSuites([suite]); diff --git a/test/visual/tabs.test.ts b/test/visual/tabs.test.ts new file mode 100644 index 0000000000..1829134d38 --- /dev/null +++ b/test/visual/tabs.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/tabs'; + +runTestSuites([suite]); diff --git a/test/visual/tag-editor.test.ts b/test/visual/tag-editor.test.ts new file mode 100644 index 0000000000..8edbf8e05d --- /dev/null +++ b/test/visual/tag-editor.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/tag-editor'; + +runTestSuites([suite]); diff --git a/test/visual/text-content.test.ts b/test/visual/text-content.test.ts new file mode 100644 index 0000000000..9bc8a0e784 --- /dev/null +++ b/test/visual/text-content.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/text-content'; + +runTestSuites([suite]); diff --git a/test/visual/text-filter.test.ts b/test/visual/text-filter.test.ts new file mode 100644 index 0000000000..218fd62481 --- /dev/null +++ b/test/visual/text-filter.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/text-filter'; + +runTestSuites([suite]); diff --git a/test/visual/textarea.test.ts b/test/visual/textarea.test.ts new file mode 100644 index 0000000000..3282ff813b --- /dev/null +++ b/test/visual/textarea.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/textarea'; + +runTestSuites([suite]); diff --git a/test/visual/tiles.test.ts b/test/visual/tiles.test.ts new file mode 100644 index 0000000000..3d7d1e5329 --- /dev/null +++ b/test/visual/tiles.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/tiles'; + +runTestSuites([suite]); diff --git a/test/visual/time-input.test.ts b/test/visual/time-input.test.ts new file mode 100644 index 0000000000..0d96ace144 --- /dev/null +++ b/test/visual/time-input.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/time-input'; + +runTestSuites([suite]); diff --git a/test/visual/toggle-button.test.ts b/test/visual/toggle-button.test.ts new file mode 100644 index 0000000000..be636ceb49 --- /dev/null +++ b/test/visual/toggle-button.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/toggle-button'; + +runTestSuites([suite]); diff --git a/test/visual/toggle.test.ts b/test/visual/toggle.test.ts new file mode 100644 index 0000000000..2ea4312468 --- /dev/null +++ b/test/visual/toggle.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/toggle'; + +runTestSuites([suite]); diff --git a/test/visual/token-group.test.ts b/test/visual/token-group.test.ts new file mode 100644 index 0000000000..7e20f831e4 --- /dev/null +++ b/test/visual/token-group.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/token-group'; + +runTestSuites([suite]); diff --git a/test/visual/top-navigation.test.ts b/test/visual/top-navigation.test.ts new file mode 100644 index 0000000000..12d9ed80d8 --- /dev/null +++ b/test/visual/top-navigation.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/top-navigation'; + +runTestSuites([suite]); diff --git a/test/visual/tree-view.test.ts b/test/visual/tree-view.test.ts new file mode 100644 index 0000000000..e9cb8d76c7 --- /dev/null +++ b/test/visual/tree-view.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/tree-view'; + +runTestSuites([suite]); diff --git a/test/visual/wizard.test.ts b/test/visual/wizard.test.ts new file mode 100644 index 0000000000..45ee321225 --- /dev/null +++ b/test/visual/wizard.test.ts @@ -0,0 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +import { runTestSuites } from '../definitions/utils'; +import suite from '../definitions/visual/wizard'; + +runTestSuites([suite]); diff --git a/tsconfig.test-definitions.json b/tsconfig.test-definitions.json index 30e82b4047..3f5961a78b 100644 --- a/tsconfig.test-definitions.json +++ b/tsconfig.test-definitions.json @@ -16,5 +16,5 @@ "skipLibCheck": true }, "include": ["test/definitions", "test/types.ts"], - "exclude": [] + "exclude": ["test/definitions/utils.ts"] } diff --git a/tsconfig.visual.json b/tsconfig.visual.json new file mode 100644 index 0000000000..be61d962ef --- /dev/null +++ b/tsconfig.visual.json @@ -0,0 +1,4 @@ +{ + "extends": "./tsconfig.integ.json", + "include": ["test/definitions/utils.ts", "test/visual/**/*.test.ts", "types"] +}