mirror of
https://github.com/Choices-js/Choices.git
synced 2026-03-14 22:55:46 +01:00
Playwright for e2e tests
This commit is contained in:
parent
72528442c7
commit
d1de64e8a0
28 changed files with 279 additions and 4473 deletions
|
|
@ -11,8 +11,7 @@
|
|||
"env": {
|
||||
"es6": true,
|
||||
"node": true,
|
||||
"browser": true,
|
||||
"cypress/globals": true
|
||||
"browser": true
|
||||
},
|
||||
"parserOptions": {
|
||||
"sourceType": "module",
|
||||
|
|
@ -65,6 +64,7 @@
|
|||
}
|
||||
],
|
||||
"lines-between-class-members": "off",
|
||||
"@typescript-eslint/no-floating-promises": "error",
|
||||
"@typescript-eslint/no-namespace": "off",
|
||||
"react/jsx-filename-extension": [0],
|
||||
"import/extensions": [
|
||||
|
|
@ -100,16 +100,6 @@
|
|||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": ["cypress/**"],
|
||||
"plugins": ["cypress"],
|
||||
"rules": {
|
||||
"no-unused-vars": "warn"
|
||||
},
|
||||
"env": {
|
||||
"cypress/globals": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"settings": {
|
||||
|
|
|
|||
131
.github/workflows/browsers.yml
vendored
131
.github/workflows/browsers.yml
vendored
|
|
@ -1,131 +0,0 @@
|
|||
name: Browsers
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- 'src/**'
|
||||
- 'package-lock.json'
|
||||
- '.browserslistrc'
|
||||
- '.babelrc'
|
||||
- 'webpack.config.*'
|
||||
- 'public/index.html'
|
||||
- '.github/actions-scripts/__snapshots__/**'
|
||||
- '.github/workflows/browsers.yml'
|
||||
|
||||
jobs:
|
||||
selenium:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [windows-latest, macos-latest]
|
||||
browser: [edge, firefox, safari, chrome]
|
||||
exclude:
|
||||
- os: windows-latest
|
||||
browser: safari
|
||||
- os: macos-latest
|
||||
browser: edge
|
||||
- os: macos-latest
|
||||
browser: chrome
|
||||
# Safari workaround is not working in Catalina
|
||||
- browser: safari
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: Dump GitHub context
|
||||
env:
|
||||
GITHUB_CONTEXT: ${{ toJson(github) }}
|
||||
run: echo "$GITHUB_CONTEXT"
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 1
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
|
||||
- name: Cache node modules
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.npm
|
||||
key: ${{ runner.OS }}-build-${{ matrix.browser }}
|
||||
restore-keys: |
|
||||
${{ runner.OS }}-build-${{ env.cache-name }}-
|
||||
${{ runner.OS }}-build-
|
||||
${{ runner.OS }}-
|
||||
|
||||
- run: |
|
||||
npm ci --no-audit
|
||||
npm run build
|
||||
env:
|
||||
CYPRESS_INSTALL_BINARY: 0
|
||||
HUSKY_SKIP_INSTALL: true
|
||||
|
||||
# install drivers
|
||||
- name: Enable Safari Driver
|
||||
run: |
|
||||
# Workaround for `sudo safardriver --enable` not working:
|
||||
# https://github.com/web-platform-tests/wpt/issues/19845
|
||||
# https://github.com/web-platform-tests/wpt/blob/master/tools/ci/azure/install_safari.yml
|
||||
mkdir -p ~/Library/WebDriver/
|
||||
curl https://raw.githubusercontent.com/web-platform-tests/wpt/master/tools/ci/azure/com.apple.Safari.plist -o ~/Library/WebDriver/com.apple.Safari.plist
|
||||
defaults write com.apple.Safari WebKitJavaScriptCanOpenWindowsAutomatically 1
|
||||
# sudo safaridriver --enable
|
||||
if: matrix.browser == 'safari'
|
||||
|
||||
- run: |
|
||||
brew install --cask firefox
|
||||
brew install geckodriver
|
||||
if: matrix.browser == 'firefox' && matrix.os == 'macos-latest'
|
||||
|
||||
- run: echo "$env:GeckoWebDriver" >> $GITHUB_PATH
|
||||
if: matrix.browser == 'firefox' && matrix.os == 'windows-latest'
|
||||
|
||||
- run: echo "$env:EdgeWebDriver" >> $GITHUB_PATH
|
||||
if: matrix.browser == 'edge' && matrix.os == 'windows-latest'
|
||||
|
||||
- run: echo "$env:ChromeWebDriver" >> $GITHUB_PATH
|
||||
if: matrix.browser == 'chrome' && matrix.os == 'windows-latest'
|
||||
|
||||
- run: npm i --no-optional --no-audit selenium-webdriver pixelmatch@5.3.0 pngjs
|
||||
- run: node .github/actions-scripts/selenium.cjs
|
||||
env:
|
||||
BROWSER: ${{ matrix.browser }}
|
||||
PORT: 0
|
||||
NODE_ENV: production # prevent watching
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: failure()
|
||||
with:
|
||||
name: screenshot-${{ matrix.browser }}-${{ matrix.os }}
|
||||
path: screenshot
|
||||
|
||||
puppeteer:
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 1
|
||||
- name: Cache node modules
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.npm
|
||||
key: ${{ runner.OS }}-build-puppeteer
|
||||
restore-keys: |
|
||||
${{ runner.OS }}-build-puppeteer
|
||||
- run: |
|
||||
npm ci --no-audit
|
||||
npm run build
|
||||
env:
|
||||
CYPRESS_INSTALL_BINARY: 0
|
||||
HUSKY_SKIP_INSTALL: true
|
||||
- run: npm i --no-optional --no-audit puppeteer@23.0.1 pixelmatch@5.3.0 pngjs@6.0.0
|
||||
- run: node .github/actions-scripts/puppeteer.cjs
|
||||
env:
|
||||
PORT: 0
|
||||
NODE_ENV: production # prevent watching
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: failure()
|
||||
with:
|
||||
name: screenshot-puppeteer-darwin
|
||||
path: screenshot
|
||||
1
.github/workflows/bundlesize.yml
vendored
1
.github/workflows/bundlesize.yml
vendored
|
|
@ -25,7 +25,6 @@ jobs:
|
|||
npm ci
|
||||
npm run build
|
||||
env:
|
||||
CYPRESS_INSTALL_BINARY: 0
|
||||
HUSKY_SKIP_INSTALL: true
|
||||
|
||||
# we don't need to build here, as even minized assets expected to be commited
|
||||
|
|
|
|||
5
.github/workflows/deploy-pages.yml
vendored
5
.github/workflows/deploy-pages.yml
vendored
|
|
@ -3,8 +3,8 @@ name: Deploy Pages
|
|||
on:
|
||||
release:
|
||||
types: [published]
|
||||
workflow_dispatch:
|
||||
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
deploy-gh-pages:
|
||||
runs-on: ubuntu-latest
|
||||
|
|
@ -22,7 +22,6 @@ jobs:
|
|||
npm run build
|
||||
rm -rf public/test
|
||||
env:
|
||||
CYPRESS_INSTALL_BINARY: 0
|
||||
HUSKY_SKIP_INSTALL: true
|
||||
- name: Deploy
|
||||
uses: peaceiris/actions-gh-pages@v3
|
||||
|
|
|
|||
1
.github/workflows/deployment.yml
vendored
1
.github/workflows/deployment.yml
vendored
|
|
@ -17,7 +17,6 @@ jobs:
|
|||
registry-url: https://registry.npmjs.org/
|
||||
- run: npm ci
|
||||
env:
|
||||
CYPRESS_INSTALL_BINARY: 0
|
||||
HUSKY_SKIP_INSTALL: true
|
||||
- run: npm publish
|
||||
env:
|
||||
|
|
|
|||
71
.github/workflows/e2e-tests.yml
vendored
71
.github/workflows/e2e-tests.yml
vendored
|
|
@ -1,71 +0,0 @@
|
|||
name: End-to-end tests
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- 'src/**'
|
||||
- 'package-lock.json'
|
||||
- '.browserslistrc'
|
||||
- '.babelrc'
|
||||
- 'webpack.config.*'
|
||||
- 'public/test/**'
|
||||
- 'cypress/**'
|
||||
- '.github/workflows/e2e-tests.yml'
|
||||
|
||||
jobs:
|
||||
test-e2e:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
CI: true
|
||||
TERM: xterm-256color
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 1
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
|
||||
- name: Cache node modules
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.npm
|
||||
key: ${{ runner.OS }}-build-${{ hashFiles('**/package-lock.json') }}
|
||||
restore-keys: |
|
||||
${{ runner.OS }}-build-${{ env.cache-name }}-
|
||||
${{ runner.OS }}-build-
|
||||
${{ runner.OS }}-
|
||||
|
||||
- name: Get Cypress info
|
||||
id: cypress-info
|
||||
run: |
|
||||
echo ::set-output name=version::$(jq -r .devDependencies.cypress ./package.json)
|
||||
echo ::set-output name=cache::$(npm exec cypress cache path)
|
||||
env:
|
||||
CYPRESS_INSTALL_BINARY: 0
|
||||
- name: Cache Cypress cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ${{ steps.cypress-info.outputs.cache }}
|
||||
key: ${{ runner.OS }}-cypress-${{ steps.cypress-info.outputs.version }}
|
||||
restore-keys: |
|
||||
${{ runner.OS }}-cypress-${{ steps.cypress-info.outputs.version }}
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci --no-audit
|
||||
env:
|
||||
HUSKY_SKIP_INSTALL: true
|
||||
|
||||
- name: run Cypress (with or without recording)
|
||||
# if we have ran out of free Cypress recordings, run Cypress with recording switched off
|
||||
run: npm exec -- run-p --race start cypress:ci || npm exec -- run-p --race start cypress:run
|
||||
env:
|
||||
NODE_ENV: production # prevent watching
|
||||
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
|
||||
DEBUG: commit-info,cypress:server:record
|
||||
# https://docs.cypress.io/guides/guides/continuous-integration.html#Environment-variables
|
||||
COMMIT_INFO_BRANCH: ${{ github.head_ref }}
|
||||
COMMIT_INFO_AUTHOR: ${{ github.event.sender.login }}
|
||||
COMMIT_INFO_SHA: ${{ github.event.after }}
|
||||
1
.github/workflows/lint.yml
vendored
1
.github/workflows/lint.yml
vendored
|
|
@ -23,7 +23,6 @@ jobs:
|
|||
- name: Install dependencies
|
||||
run: npm ci
|
||||
env:
|
||||
CYPRESS_INSTALL_BINARY: 0
|
||||
HUSKY_SKIP_INSTALL: true
|
||||
|
||||
- name: run eslint
|
||||
|
|
|
|||
59
.github/workflows/playwright.yml
vendored
Normal file
59
.github/workflows/playwright.yml
vendored
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
name: Playwright Tests
|
||||
on:
|
||||
push:
|
||||
branches: [ playwright ]
|
||||
pull_request:
|
||||
branches: [ main, master ]
|
||||
jobs:
|
||||
test:
|
||||
timeout-minutes: 60
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [windows-latest, macos-latest, ubuntu-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: lts/*
|
||||
- name: Cache node modules
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.npm
|
||||
key: ${{ runner.OS }}-build
|
||||
restore-keys: |
|
||||
${{ runner.OS }}-build-
|
||||
${{ runner.OS }}-
|
||||
- name: Install dependencies
|
||||
run: npm ci --no-audit
|
||||
|
||||
- name: Get installed Playwright version
|
||||
id: playwright-version
|
||||
run: echo "PLAYWRIGHT_VERSION=$(node -e "console.log(require('./package-lock.json').dependencies['@playwright/test'].version)")" >> $GITHUB_ENV
|
||||
- name: Cache playwright binaries
|
||||
uses: actions/cache@v3
|
||||
id: playwright-cache
|
||||
with:
|
||||
path: |
|
||||
~/.cache/ms-playwright
|
||||
key: ${{ runner.os }}-playwright-${{ env.PLAYWRIGHT_VERSION }}
|
||||
- name: Install Playwright Browsers
|
||||
run: npx playwright install --with-deps
|
||||
if: steps.playwright-cache.outputs.cache-hit != 'true'
|
||||
- run: npx playwright install-deps
|
||||
if: steps.playwright-cache.outputs.cache-hit != 'true'
|
||||
|
||||
- name: Run Playwright tests
|
||||
run: npx playwright test
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: failure()
|
||||
with:
|
||||
name: screenshot-${{ matrix.os }}
|
||||
path: screenshot
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: always()
|
||||
with:
|
||||
name: playwright-report
|
||||
path: playwright-report/
|
||||
retention-days: 30
|
||||
1
.github/workflows/unit-tests.yml
vendored
1
.github/workflows/unit-tests.yml
vendored
|
|
@ -22,7 +22,6 @@ jobs:
|
|||
- name: Install dependencies
|
||||
run: npm ci --no-audit
|
||||
env:
|
||||
CYPRESS_INSTALL_BINARY: 0
|
||||
HUSKY_SKIP_INSTALL: true
|
||||
|
||||
- run: npm run build
|
||||
|
|
|
|||
6
.gitignore
vendored
6
.gitignore
vendored
|
|
@ -11,5 +11,7 @@ tests/reports
|
|||
tests/results
|
||||
.nyc_output
|
||||
coverage
|
||||
cypress/videos
|
||||
cypress/screenshots
|
||||
/test-results/
|
||||
/playwright-report/
|
||||
/blob-report/
|
||||
/playwright/.cache/
|
||||
|
|
|
|||
30
.vscode/launch.json
vendored
30
.vscode/launch.json
vendored
|
|
@ -12,35 +12,5 @@
|
|||
"webpack://Choices/*": "${workspaceFolder}/*"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"name": "Cypress Current File",
|
||||
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/cypress",
|
||||
"windows": {
|
||||
"runtimeExecutable": "${workspaceFolder}\\node_modules\\.bin\\cypress.cmd"
|
||||
},
|
||||
"runtimeArgs": [
|
||||
"run",
|
||||
"--headed",
|
||||
"--no-exit",
|
||||
"--browser=electron",
|
||||
"--port",
|
||||
"9898",
|
||||
"--spec"
|
||||
],
|
||||
"protocol": "legacy",
|
||||
"port": 9898,
|
||||
"program": "${file}",
|
||||
"console": "integratedTerminal",
|
||||
"preLaunchTask": "buildAndWatch",
|
||||
"internalConsoleOptions": "openOnSessionStart",
|
||||
"timeout": 999999999999999,
|
||||
"autoAttachChildProcesses": false,
|
||||
"env": {
|
||||
"NODE_ENV": "test"
|
||||
// "DEBUG": "cypress:*"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
5
.vscode/settings.json
vendored
5
.vscode/settings.json
vendored
|
|
@ -38,11 +38,6 @@
|
|||
"npm.fetchOnlinePackageInfo": true,
|
||||
"eslint.packageManager": "npm",
|
||||
"json.schemas": [
|
||||
// Cypress related settings - https://docs.cypress.io/guides/tooling/intelligent-code-completion.html#Features-1
|
||||
{
|
||||
"fileMatch": ["cypress.json"],
|
||||
"url": "https://on.cypress.io/cypress.schema.json"
|
||||
},
|
||||
// Husky config file
|
||||
{
|
||||
"fileMatch": [".huskyrc"],
|
||||
|
|
|
|||
5
.vscode/tasks.json
vendored
5
.vscode/tasks.json
vendored
|
|
@ -78,10 +78,5 @@
|
|||
"script": "test:unit",
|
||||
"group": "test"
|
||||
},
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "cypress:open",
|
||||
"isBackground": true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,9 @@
|
|||
* Restructure end-to-end tests so html/script blocks are co-located to improve debugability
|
||||
* Enable `@typescript-eslint/explicit-function-return-type` eslint rule
|
||||
|
||||
### Chore
|
||||
* Switch e2e tests from `puppeteer`/`selenium`/`cypress` `playwright`
|
||||
|
||||
## [11.0.0-rc6] (2024-08-12)
|
||||
|
||||
### Features
|
||||
|
|
|
|||
16
README.md
16
README.md
|
|
@ -1229,17 +1229,27 @@ To setup a local environment: clone this repo, navigate into its directory in a
|
|||
|
||||
`npm install`
|
||||
|
||||
### playwright
|
||||
|
||||
e2e (End-to-end) tests are implemented using playwright, which requires installing likely with OS support.
|
||||
|
||||
`npx playwright install`
|
||||
`npx playwright install-deps `
|
||||
|
||||
For JetBrain IDE's the `Test automation` plugin is recommended:
|
||||
https://www.jetbrains.com/help/phpstorm/playwright.html
|
||||
|
||||
### NPM tasks
|
||||
|
||||
| Task | Usage |
|
||||
| ------------------------- | ------------------------------------------------------------ |
|
||||
|---------------------------|--------------------------------------------------------------|
|
||||
| `npm run start` | Fire up local server for development |
|
||||
| `npm run test:unit` | Run sequence of tests once |
|
||||
| `npm run test:unit:watch` | Fire up test server and re-test on file change |
|
||||
| `npm run test:e2e` | Run sequence of e2e tests (with local server) |
|
||||
| `npm run test` | Run both unit and e2e tests |
|
||||
| `npm run cypress:open` | Run Cypress e2e tests (GUI) |
|
||||
| `npm run cypress:run` | Run Cypress e2e tests (CLI) |
|
||||
| `npm run playwright:gui` | Run Playwright e2e tests (GUI) |
|
||||
| `npm run playwright:cli` | Run Playwright e2e tests (CLI) |
|
||||
| `npm run js:build` | Compile Choices to an uglified JavaScript file |
|
||||
| `npm run css:watch` | Watch SCSS files for changes. On a change, run build process |
|
||||
| `npm run css:build` | Compile, minify and prefix SCSS files to CSS |
|
||||
|
|
|
|||
|
|
@ -1,10 +0,0 @@
|
|||
import { defineConfig } from 'cypress';
|
||||
|
||||
export default defineConfig({
|
||||
video: false,
|
||||
projectId: 'n7g5qp',
|
||||
e2e: {
|
||||
baseUrl: 'http://localhost:3001/test',
|
||||
specPattern: 'cypress/e2e/**/*.{js,jsx,ts,tsx}',
|
||||
},
|
||||
});
|
||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -1,413 +0,0 @@
|
|||
describe('Choices - text element', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('/text', {
|
||||
onBeforeLoad(win) {
|
||||
cy.stub(win.console, 'warn').as('consoleWarn');
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
describe('scenarios', () => {
|
||||
const textInput = 'testing';
|
||||
|
||||
describe('basic', () => {
|
||||
describe('adding items', () => {
|
||||
it('allows me to input items', () => {
|
||||
cy.get('[data-test-hook=basic]')
|
||||
.find('.choices__input--cloned')
|
||||
.type(textInput)
|
||||
.type('{enter}');
|
||||
|
||||
cy.get('[data-test-hook=basic]')
|
||||
.find('.choices__list--multiple .choices__item')
|
||||
.last()
|
||||
.should(($el) => {
|
||||
expect($el).to.contain(textInput);
|
||||
});
|
||||
});
|
||||
|
||||
it('updates the value of the original input', () => {
|
||||
cy.get('[data-test-hook=basic]')
|
||||
.find('.choices__input--cloned')
|
||||
.type(textInput)
|
||||
.type('{enter}');
|
||||
|
||||
cy.get('[data-test-hook=basic]')
|
||||
.find('.choices__input[hidden]')
|
||||
.should('have.value', textInput);
|
||||
});
|
||||
|
||||
describe('inputting data', () => {
|
||||
it('shows a dropdown prompt', () => {
|
||||
cy.get('[data-test-hook=basic]')
|
||||
.find('.choices__input--cloned')
|
||||
.type(textInput);
|
||||
|
||||
cy.get('[data-test-hook=basic]')
|
||||
.find('.choices__list--dropdown')
|
||||
.should('be.visible')
|
||||
.should(($dropdown) => {
|
||||
const dropdownText = $dropdown.text().trim();
|
||||
expect(dropdownText).to.equal(
|
||||
`Press Enter to add "${textInput}"`,
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('editing items', () => {
|
||||
beforeEach(() => {
|
||||
for (let index = 0; index < 3; index++) {
|
||||
cy.get('[data-test-hook=edit-items]')
|
||||
.find('.choices__input--cloned')
|
||||
.type(textInput)
|
||||
.type('{enter}');
|
||||
}
|
||||
});
|
||||
|
||||
describe('on back space', () => {
|
||||
it('allows me to change my entry', () => {
|
||||
cy.get('[data-test-hook=edit-items]')
|
||||
.find('.choices__input--cloned')
|
||||
.type('{backspace}')
|
||||
.type('-edited')
|
||||
.type('{enter}');
|
||||
|
||||
cy.get('[data-test-hook=edit-items]')
|
||||
.find('.choices__list--multiple .choices__item')
|
||||
.last()
|
||||
.should(($choice) => {
|
||||
expect($choice.data('value')).to.equal(`${textInput}-edited`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('on cmd+a', () => {
|
||||
beforeEach(() => {
|
||||
cy.get('[data-test-hook=edit-items]')
|
||||
.find('.choices__input--cloned')
|
||||
.type('{cmd}a');
|
||||
});
|
||||
|
||||
it('highlights all items', () => {
|
||||
cy.get('[data-test-hook=edit-items]')
|
||||
.find('.choices__list--multiple .choices__item')
|
||||
.each(($choice) => {
|
||||
expect($choice.hasClass('is-highlighted')).to.equal(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('on backspace', () => {
|
||||
it('clears all inputted values', () => {
|
||||
// two backspaces are needed as Cypress has an issue where
|
||||
// it will also insert an 'a' character into the text input
|
||||
cy.get('[data-test-hook=edit-items]')
|
||||
.find('.choices__input--cloned')
|
||||
.type('{backspace}{backspace}');
|
||||
|
||||
cy.get('[data-test-hook=edit-items]')
|
||||
.find('.choices__list--multiple .choices__item')
|
||||
.should('have.length', 0);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('remove button', () => {
|
||||
beforeEach(() => {
|
||||
cy.get('[data-test-hook=remove-button]')
|
||||
.find('.choices__input--cloned')
|
||||
.type(`${textInput}`)
|
||||
.type('{enter}');
|
||||
});
|
||||
|
||||
describe('on click', () => {
|
||||
it('removes respective choice', () => {
|
||||
cy.get('[data-test-hook=remove-button]')
|
||||
.find('.choices__list--multiple')
|
||||
.children()
|
||||
.should(($items) => {
|
||||
expect($items.length).to.equal(1);
|
||||
});
|
||||
|
||||
cy.get('[data-test-hook=remove-button]')
|
||||
.find('.choices__list--multiple .choices__item')
|
||||
.last()
|
||||
.find('.choices__button')
|
||||
.focus()
|
||||
.click();
|
||||
|
||||
cy.get('[data-test-hook=remove-button]')
|
||||
.find('.choices__list--multiple .choices__item')
|
||||
.should(($items) => {
|
||||
expect($items.length).to.equal(0);
|
||||
});
|
||||
});
|
||||
|
||||
it('updates the value of the original input', () => {
|
||||
cy.get('[data-test-hook=remove-button]')
|
||||
.find('.choices__list--multiple .choices__item')
|
||||
.last()
|
||||
.find('.choices__button')
|
||||
.focus()
|
||||
.click();
|
||||
|
||||
cy.get('[data-test-hook=remove-button]')
|
||||
.find('.choices__input[hidden]')
|
||||
.then(($input) => {
|
||||
expect($input.val()).to.not.contain(textInput);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('unique values only', () => {
|
||||
describe('unique values', () => {
|
||||
beforeEach(() => {
|
||||
cy.get('[data-test-hook=unique-values]')
|
||||
.find('.choices__input--cloned')
|
||||
.type(`${textInput}`)
|
||||
.type('{enter}')
|
||||
.type(`${textInput}`)
|
||||
.type('{enter}');
|
||||
});
|
||||
|
||||
it('only allows me to input unique values', () => {
|
||||
cy.get('[data-test-hook=unique-values]')
|
||||
.find('.choices__list--multiple')
|
||||
.first()
|
||||
.children()
|
||||
.should(($items) => {
|
||||
expect($items.length).to.equal(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('inputting a non-unique value', () => {
|
||||
it('displays dropdown prompt', () => {
|
||||
cy.get('[data-test-hook=unique-values]')
|
||||
.find('.choices__list--dropdown')
|
||||
.should('be.visible')
|
||||
.should(($dropdown) => {
|
||||
const dropdownText = $dropdown.text().trim();
|
||||
expect(dropdownText).to.equal(
|
||||
'Only unique values can be added',
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('input limit', () => {
|
||||
const inputLimit = 5;
|
||||
beforeEach(() => {
|
||||
for (let index = 0; index < inputLimit + 1; index++) {
|
||||
cy.get('[data-test-hook=input-limit]')
|
||||
.find('.choices__input--cloned')
|
||||
.type(`${textInput} + ${index}`)
|
||||
.type('{enter}');
|
||||
}
|
||||
});
|
||||
|
||||
it('does not let me input more than 5 choices', () => {
|
||||
cy.get('[data-test-hook=input-limit]')
|
||||
.find('.choices__list--multiple')
|
||||
.first()
|
||||
.children()
|
||||
.should(($items) => {
|
||||
expect($items.length).to.equal(inputLimit);
|
||||
});
|
||||
});
|
||||
|
||||
describe('reaching input limit', () => {
|
||||
it('displays dropdown prompt', () => {
|
||||
cy.get('[data-test-hook=input-limit]')
|
||||
.find('.choices__list--dropdown')
|
||||
.should('be.visible')
|
||||
.should(($dropdown) => {
|
||||
const dropdownText = $dropdown.text().trim();
|
||||
expect(dropdownText).to.equal(
|
||||
`Only ${inputLimit} values can be added`,
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('add item filter', () => {
|
||||
describe('inputting a value that satisfies the filter', () => {
|
||||
const input = 'joe@bloggs.com';
|
||||
|
||||
it('allows me to add choice', () => {
|
||||
cy.get('[data-test-hook=add-item-filter]')
|
||||
.find('.choices__input--cloned')
|
||||
.type(input)
|
||||
.type('{enter}');
|
||||
|
||||
cy.get('[data-test-hook=add-item-filter]')
|
||||
.find('.choices__list--multiple .choices__item')
|
||||
.last()
|
||||
.should(($choice) => {
|
||||
expect($choice.text().trim()).to.equal(input);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('inputting a value that does not satisfy the regex', () => {
|
||||
it('displays dropdown prompt', () => {
|
||||
cy.get('[data-test-hook=add-item-filter]')
|
||||
.find('.choices__input--cloned')
|
||||
.type(`this is not an email address`)
|
||||
.type('{enter}');
|
||||
|
||||
cy.get('[data-test-hook=add-item-filter]')
|
||||
.find('.choices__list--dropdown')
|
||||
.should('be.visible')
|
||||
.should(($dropdown) => {
|
||||
const dropdownText = $dropdown.text().trim();
|
||||
expect(dropdownText).to.equal(
|
||||
'Only values matching specific conditions can be added',
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('prepend/append', () => {
|
||||
beforeEach(() => {
|
||||
cy.get('[data-test-hook=prepend-append]')
|
||||
.find('.choices__input--cloned')
|
||||
.type(textInput)
|
||||
.type('{enter}');
|
||||
});
|
||||
|
||||
it('prepends and appends value to inputted value', () => {
|
||||
cy.get('[data-test-hook=prepend-append]')
|
||||
.find('.choices__list--multiple .choices__item')
|
||||
.last()
|
||||
.should(($choice) => {
|
||||
expect($choice.data('value')).to.equal(`before-${textInput}-after`);
|
||||
});
|
||||
});
|
||||
|
||||
it('displays just the inputted value to the user', () => {
|
||||
cy.get('[data-test-hook=prepend-append]')
|
||||
.find('.choices__list--multiple .choices__item')
|
||||
.last()
|
||||
.should(($choice) => {
|
||||
expect($choice.text()).to.not.contain(`before-${textInput}-after`);
|
||||
expect($choice.text()).to.contain(textInput);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('adding items disabled', () => {
|
||||
it('does not allow me to input data', () => {
|
||||
cy.get('[data-test-hook=adding-items-disabled]')
|
||||
.find('.choices__input--cloned')
|
||||
.should('be.disabled');
|
||||
});
|
||||
});
|
||||
|
||||
describe('disabled via attribute', () => {
|
||||
it('does not allow me to input data', () => {
|
||||
cy.get('[data-test-hook=disabled-via-attr]')
|
||||
.find('.choices__input--cloned')
|
||||
.should('be.disabled');
|
||||
});
|
||||
});
|
||||
|
||||
describe('pre-populated choices', () => {
|
||||
it('pre-populates choices', () => {
|
||||
cy.get('[data-test-hook=prepopulated]')
|
||||
.find('.choices__list--multiple .choices__item')
|
||||
.should(($choices) => {
|
||||
expect($choices.length).to.equal(2);
|
||||
});
|
||||
|
||||
cy.get('[data-test-hook=prepopulated]')
|
||||
.find('.choices__list--multiple .choices__item')
|
||||
.first()
|
||||
.should(($choice) => {
|
||||
expect($choice.text().trim()).to.equal('Josh Johnson');
|
||||
});
|
||||
|
||||
cy.get('[data-test-hook=prepopulated]')
|
||||
.find('.choices__list--multiple .choices__item')
|
||||
.last()
|
||||
.should(($choice) => {
|
||||
expect($choice.text().trim()).to.equal('Joe Bloggs');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('placeholder', () => {
|
||||
/*
|
||||
{
|
||||
placeholder: true,
|
||||
placeholderValue: 'I am a placeholder',
|
||||
}
|
||||
*/
|
||||
describe('when no value has been inputted', () => {
|
||||
it('displays a placeholder', () => {
|
||||
cy.get('[data-test-hook=placeholder]')
|
||||
.find('.choices__input--cloned')
|
||||
.should('have.attr', 'placeholder', 'I am a placeholder');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('allow html', () => {
|
||||
describe('set to true', () => {
|
||||
it('does not show html as text', () => {
|
||||
cy.get('[data-test-hook=allowhtml-true]')
|
||||
.find('.choices__list--multiple .choices__item')
|
||||
.first()
|
||||
.should(($choice) => {
|
||||
expect($choice.text().trim()).to.equal('Mason Rogers');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('set to false', () => {
|
||||
it('shows html as text', () => {
|
||||
cy.get('[data-test-hook=allowhtml-false]')
|
||||
.find('.choices__list--multiple .choices__item')
|
||||
.first()
|
||||
.should(($choice) => {
|
||||
expect($choice.text().trim()).to.equal('<b>Mason Rogers</b>');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('within form', () => {
|
||||
describe('inputting item', () => {
|
||||
describe('on enter key', () => {
|
||||
it('does not submit form', () => {
|
||||
cy.get('[data-test-hook=within-form] form').then(($form) => {
|
||||
$form.submit(() => {
|
||||
// this will fail the test if the form submits
|
||||
throw new Error('Form submitted');
|
||||
});
|
||||
});
|
||||
|
||||
cy.get('[data-test-hook=within-form]')
|
||||
.find('.choices__input--cloned')
|
||||
.type(textInput)
|
||||
.type('{enter}');
|
||||
|
||||
cy.get('[data-test-hook=within-form]')
|
||||
.find('.choices__list--multiple .choices__item')
|
||||
.last()
|
||||
.should(($el) => {
|
||||
expect($el).to.contain(textInput);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
{
|
||||
"name": "Using fixtures to represent data",
|
||||
"email": "hello@cypress.io",
|
||||
"body": "Fixtures are a great way to mock data for responses to routes"
|
||||
}
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
// ***********************************************
|
||||
// This example commands.js shows you how to
|
||||
// create various custom commands and overwrite
|
||||
// existing commands.
|
||||
//
|
||||
// For more comprehensive examples of custom
|
||||
// commands please read more here:
|
||||
// https://on.cypress.io/custom-commands
|
||||
// ***********************************************
|
||||
//
|
||||
//
|
||||
// -- This is a parent command --
|
||||
// Cypress.Commands.add("login", (email, password) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This is a child command --
|
||||
// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This is a dual command --
|
||||
// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This is will overwrite an existing command --
|
||||
// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
// ***********************************************************
|
||||
// This example support/index.js is processed and
|
||||
// loaded automatically before your test files.
|
||||
//
|
||||
// This is a great place to put global configuration and
|
||||
// behavior that modifies Cypress.
|
||||
//
|
||||
// You can change the location of this file or turn off
|
||||
// automatically serving support files with the
|
||||
// 'supportFile' configuration option.
|
||||
//
|
||||
// You can read more here:
|
||||
// https://on.cypress.io/configuration
|
||||
// ***********************************************************
|
||||
|
||||
// Import commands.js using ES2015 syntax:
|
||||
import './commands';
|
||||
|
||||
// Alternatively you can use CommonJS syntax:
|
||||
// require('./commands')
|
||||
|
|
@ -3,20 +3,21 @@
|
|||
"module": "es6",
|
||||
"lib": ["es2017", "dom"],
|
||||
"target": "es5",
|
||||
"moduleResolution": "node",
|
||||
"moduleResolution": "bundler",
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"resolveJsonModule": true,
|
||||
"esModuleInterop": true,
|
||||
"strict": false,
|
||||
"noImplicitAny": false,
|
||||
"declaration": true,
|
||||
"allowJs": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"strictNullChecks": true,
|
||||
"newLine": "lf",
|
||||
"types": ["cypress", "node"],
|
||||
"declarationDir": "../public/types/cypress"
|
||||
"declaration": false,
|
||||
"declarationMap": false,
|
||||
"types": [],
|
||||
},
|
||||
"include": ["."]
|
||||
}
|
||||
"include": [".", "../src"],
|
||||
"exclude": ["**/node_modules", "**/public"]
|
||||
}
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
"checkJs": true,
|
||||
"target": "es2020",
|
||||
"lib": ["esnext", "dom"],
|
||||
"types": ["cypress"],
|
||||
"types": [],
|
||||
"strict": true,
|
||||
"moduleResolution": "node",
|
||||
/* Additional Checks */
|
||||
|
|
|
|||
1595
package-lock.json
generated
1595
package-lock.json
generated
File diff suppressed because it is too large
Load diff
13
package.json
13
package.json
|
|
@ -30,17 +30,16 @@
|
|||
"start": "run-p js:watch css:watch",
|
||||
"build": "run-p js:build css:build",
|
||||
"lint": "run-p lint:js lint:scss",
|
||||
"lint:js": "eslint src/scripts test/scripts",
|
||||
"lint:js": "eslint src/scripts test/scripts e2e",
|
||||
"lint:scss": "stylelint src/**/*.scss",
|
||||
"bundlesize": "bundlesize",
|
||||
"cypress:run": "cypress run --config-file cypress/cypress.config.ts --browser chromium",
|
||||
"cypress:open": "cypress open --config-file cypress/cypress.config.ts ",
|
||||
"cypress:ci": "cypress run --config-file cypress/cypress.config.ts --browser chromium --record --group $GITHUB_REF --ci-build-id $GITHUB_SHA",
|
||||
"playwright:cli": "playwright test",
|
||||
"playwright:gui": "playwright test --ui",
|
||||
"test": "run-s test:unit test:e2e",
|
||||
"test:unit": "vitest --config test/vitest.config.ts run",
|
||||
"test:unit:watch": "npm run test:unit -- --watch --inspect=5556",
|
||||
"test:unit:coverage": "vitest --config test/vitest.config.ts run --coverage",
|
||||
"test:e2e": "run-p --race start cypress:run",
|
||||
"test:e2e": "run-s playwright:cli",
|
||||
"js:watch": "rollup -w --bundleConfigAsCjs -c scripts/rollup.config.mjs --environment TARGET:. --environment OUTPUT_TYPES:umd --environment WATCH_HOST:localhost",
|
||||
"js:build": "rollup --bundleConfigAsCjs -c scripts/rollup.config.mjs --environment WITH_D_TS_FILES:1 && mv public/assets/scripts/src public/types/",
|
||||
"js:build-dev": "rollup --bundleConfigAsCjs -c scripts/rollup.config.mjs --environment TARGET:. --environment OUTPUT_TYPES:umd",
|
||||
|
|
@ -83,6 +82,7 @@
|
|||
"@babel/plugin-transform-object-rest-spread": "^7.24.7",
|
||||
"@babel/preset-env": "^7.25.3",
|
||||
"@babel/preset-typescript": "^7.24.7",
|
||||
"@playwright/test": "^1.46.0",
|
||||
"@rollup/plugin-babel": "^6.0.4",
|
||||
"@rollup/plugin-eslint": "^9.0.5",
|
||||
"@rollup/plugin-node-resolve": "^15.2.3",
|
||||
|
|
@ -90,6 +90,7 @@
|
|||
"@rollup/plugin-terser": "^0.4.4",
|
||||
"@rollup/plugin-typescript": "^11.1.6",
|
||||
"@types/chai": "^4.3.17",
|
||||
"@types/node": "^22.2.0",
|
||||
"@types/sinon": "^17.0.3",
|
||||
"@types/sinon-chai": "^3.2.12",
|
||||
"@vitest/coverage-v8": "^2.0.5",
|
||||
|
|
@ -97,13 +98,11 @@
|
|||
"bundlesize": "^0.18.2",
|
||||
"chai": "^5.1.1",
|
||||
"csso-cli": "^4.0.2",
|
||||
"cypress": "^13.13.2",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-airbnb-base": "^15.0.0",
|
||||
"eslint-config-airbnb-typescript": "^18.0.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-plugin-compat": "6.0.0",
|
||||
"eslint-plugin-cypress": "^3.4.0",
|
||||
"eslint-plugin-import": "^2.29.1",
|
||||
"eslint-plugin-prettier": "^5.2.1",
|
||||
"eslint-plugin-sort-class-members": "^1.20.0",
|
||||
|
|
|
|||
82
playwright.config.ts
Normal file
82
playwright.config.ts
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
import { defineConfig, devices } from '@playwright/test';
|
||||
|
||||
/**
|
||||
* Read environment variables from file.
|
||||
* https://github.com/motdotla/dotenv
|
||||
*/
|
||||
// import dotenv from 'dotenv';
|
||||
// dotenv.config({ path: path.resolve(__dirname, '.env') });
|
||||
|
||||
/**
|
||||
* See https://playwright.dev/docs/test-configuration.
|
||||
*/
|
||||
export default defineConfig({
|
||||
testDir: './e2e',
|
||||
/* Run tests in files in parallel */
|
||||
fullyParallel: true,
|
||||
/* Fail the build on CI if you accidentally left test.only in the source code. */
|
||||
forbidOnly: !!process.env.CI,
|
||||
/* Retry on CI only */
|
||||
retries: process.env.CI ? 2 : 0,
|
||||
/* Opt out of parallel tests on CI. */
|
||||
workers: process.env.CI ? 1 : undefined,
|
||||
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
||||
reporter: process.env.CI ? 'dot' : 'list',
|
||||
timeout: 1000,
|
||||
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
||||
use: {
|
||||
/* Base URL to use in actions like `await page.goto('/')`. */
|
||||
baseURL: 'http://127.0.0.1:3001/',
|
||||
|
||||
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
|
||||
trace: 'on-first-retry',
|
||||
|
||||
testIdAttribute: 'data-test-hook',
|
||||
},
|
||||
|
||||
/* Configure projects for major browsers */
|
||||
projects: [
|
||||
{
|
||||
name: 'chromium',
|
||||
use: { ...devices['Desktop Chrome'] },
|
||||
},
|
||||
/*
|
||||
{
|
||||
name: 'firefox',
|
||||
use: { ...devices['Desktop Firefox'] },
|
||||
},
|
||||
|
||||
{
|
||||
name: 'webkit',
|
||||
use: { ...devices['Desktop Safari'] },
|
||||
},
|
||||
*/
|
||||
|
||||
/* Test against mobile viewports. */
|
||||
// {
|
||||
// name: 'Mobile Chrome',
|
||||
// use: { ...devices['Pixel 5'] },
|
||||
// },
|
||||
// {
|
||||
// name: 'Mobile Safari',
|
||||
// use: { ...devices['iPhone 12'] },
|
||||
// },
|
||||
|
||||
/* Test against branded browsers. */
|
||||
// {
|
||||
// name: 'Microsoft Edge',
|
||||
// use: { ...devices['Desktop Edge'], channel: 'msedge' },
|
||||
// },
|
||||
// {
|
||||
// name: 'Google Chrome',
|
||||
// use: { ...devices['Desktop Chrome'], channel: 'chrome' },
|
||||
// },
|
||||
],
|
||||
|
||||
/* Run your local dev server before starting the tests */
|
||||
//webServer: {
|
||||
// command: 'npm run start',
|
||||
// url: 'http://127.0.0.1:3001',
|
||||
// reuseExistingServer: !process.env.CI,
|
||||
//},
|
||||
});
|
||||
|
|
@ -942,7 +942,6 @@
|
|||
</script>
|
||||
|
||||
<!-- Google Analytics - Ignore me -->
|
||||
<!-- google analytics is currently breaking puppeteer tests
|
||||
<script>
|
||||
try {
|
||||
window.ga =
|
||||
|
|
@ -958,7 +957,6 @@
|
|||
}
|
||||
</script>
|
||||
<script async src="https://www.google-analytics.com/analytics.js"></script>
|
||||
-->
|
||||
<!-- End Google Analytics -->
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue