diff --git a/.github/workflows/tests-on-pr.yml b/.github/workflows/tests-on-pr.yml
new file mode 100644
index 00000000000..e34b48647e7
--- /dev/null
+++ b/.github/workflows/tests-on-pr.yml
@@ -0,0 +1,65 @@
+name: UI Tests
+
+on:
+ pull_request:
+ types: [opened, edited, synchronize ]
+ branches:
+ - 'dev'
+ paths:
+ - 'ui/**'
+
+jobs:
+ tests:
+ runs-on: ubuntu-latest
+
+ strategy:
+ fail-fast: false
+ matrix:
+ browser: [chrome, firefox]
+
+ name: Tests on ${{ matrix.browser }}
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v3
+
+ - name: Setup node
+ uses: actions/setup-node@v3
+ with:
+ node-version: 14
+
+ - name: Install dependencies
+ run: cd ./ui && npm i
+
+ - name: Run tests in ${{ matrix.browser }} browser
+ uses: cypress-io/github-action@v2
+ with:
+ browser: ${{ matrix.browser }}
+ command: npm run test:component:ci
+ working-directory: ui
+ tag: ${{ github.event_name }} # Tag will be either "push" or "pull_request"
+ group: Tests in ${{ matrix.browser }} browser
+ env:
+ CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} # Dashboard record key as an environment variable
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # To allow accurately detecting a build vs a re-run build
+ COMMIT_INFO_MESSAGE: ${{ github.event.pull_request.title }} # Either PR title or default information
+
+ - name: Add workflow summary
+ env:
+ SUMMARY: |
+ Hi @${{ github.event.pull_request.user.login }} and thanks for the contribution! 👏
+
+ We've detected file changes inside the `ui` folder, so that triggered our Cypress component tests.
+ run: echo "$SUMMARY" >> $GITHUB_STEP_SUMMARY
+ if: always()
+
+ - name: Output failure message
+ env:
+ FAILURE: ":bangbang: Seems like some of the tests are failing. Please amend 'em for someone from the team to be able to review it."
+ run: echo "$FAILURE" >> $GITHUB_STEP_SUMMARY
+ if: failure() || cancelled()
+
+ - name: Output success message
+ env:
+ SUCCESS: ":white_check_mark: Seems like all the tests passed successfully, so your PR is ready to be reviewed!"
+ run: echo "$SUCCESS" >> $GITHUB_STEP_SUMMARY
+ if: success()
\ No newline at end of file
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 551c2f5a2c7..f3937d7199f 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -50,6 +50,8 @@ Hi! We are really excited that you are interested in contributing to Quasar 👏
- If you are resolving a special issue, add `(fix: #xxxx[,#xxx])` (#xxxx is the issue id) in your PR title for a better release log, e.g. `fix: update entities encoding/decoding (fix #3899)`.
- Provide detailed description of the bug in the PR. A live demo is preferred.
+- Cypress e2e tests will run every time there is a code change in any file of the `ui` folder.
+
## Development Setup
You will need [Node.js](http://nodejs.org) **version 12.22.1+** along [Yarn](https://yarnpkg.com/) or [NPM](https://docs.npmjs.com/getting-started/installing-node). Read `package.json` and take notice of the scripts you can use.
diff --git a/README.md b/README.md
index abb335fb417..fb65cb02e99 100644
--- a/README.md
+++ b/README.md
@@ -10,6 +10,8 @@
[![https://good-labs.github.io/greater-good-affirmation/assets/images/badge.svg](https://good-labs.github.io/greater-good-affirmation/assets/images/badge.svg)](https://good-labs.github.io/greater-good-affirmation)
+[![UI Tests](https://github.com/quasarframework/quasar/actions/workflows/tests-on-pr.yml/badge.svg?branch=dev)](https://github.com/quasarframework/quasar/actions/workflows/tests-on-pr.yml)
+
Please submit a PR to https://github.com/quasarframework/quasar-awesome with your website/app/Quasar tutorial/video etc. Thank you!
## Supporting Quasar
diff --git a/ui/dev/cypress.json b/ui/dev/cypress.json
index cd50ea9c189..734bb3e324f 100644
--- a/ui/dev/cypress.json
+++ b/ui/dev/cypress.json
@@ -1,4 +1,5 @@
{
+ "projectId": "5zr217",
"fixturesFolder": "../test/cypress/fixtures",
"screenshotsFolder": "../test/cypress/screenshots",
"pluginsFile": "../test/cypress/plugins/index.js",
diff --git a/ui/package.json b/ui/package.json
index 8969c771359..461e73a50b0 100644
--- a/ui/package.json
+++ b/ui/package.json
@@ -30,7 +30,7 @@
"lint": "eslint --ext .js,.vue src dev",
"lint-fix": "eslint --ext .js,.vue src dev --fix",
"test:component": "cd ./dev && cypress open-ct && cd ..",
- "test:component:ci": "cd ./dev && cypress run-ct && cd ..",
+ "test:component:ci": "cd ./dev && cypress run-ct --record --parallel && cd ..",
"test:create": "node ./test/cypress/helpers/create-spec.js -c"
},
"repository": {
diff --git a/ui/src/components/menu/__tests__/QMenu.spec.js b/ui/src/components/menu/__tests__/QMenu.spec.js
index 552fdc1ce1c..7b8973f55fc 100644
--- a/ui/src/components/menu/__tests__/QMenu.spec.js
+++ b/ui/src/components/menu/__tests__/QMenu.spec.js
@@ -15,7 +15,7 @@ describe('Menu API', () => {
describe('(prop): touch-position', () => {
it('should show menu at the position of the click', () => {
mount(WrapperOne, {
- attrs: {
+ props: {
'touch-position': true
}
})
@@ -71,7 +71,7 @@ describe('Menu API', () => {
it('should not close the menu when clicking outside the menu when persistent', () => {
mount(WrapperOne, {
- attrs: {
+ props: {
persistent: true
}
})
@@ -89,7 +89,7 @@ describe('Menu API', () => {
it('should not close the menu when hitting the escape key when persistent', () => {
mount(WrapperOne, {
- attrs: {
+ props: {
persistent: true
}
})
@@ -129,7 +129,7 @@ describe('Menu API', () => {
it('should close the menu when clicking a menu child without v-close-popup when auto-close is true', () => {
mount(WrapperOne, {
- attrs: {
+ props: {
'auto-close': true
}
})
@@ -174,7 +174,7 @@ describe('Menu API', () => {
it('should not switch focus back to parent element when closing if no-refocus is true', () => {
mount(WrapperOne, {
- attrs: {
+ props: {
'no-refocus': true
}
})
@@ -208,7 +208,7 @@ describe('Menu API', () => {
it('should no switch focus to the menu when opening with no-focus is true', () => {
mount(WrapperOne, {
- attrs: {
+ props: {
'no-focus': true
}
})
@@ -226,7 +226,7 @@ describe('Menu API', () => {
describe('(prop): fit', () => {
it('should show a menu that matches the full with of the target when fit is supplied', () => {
mount(WrapperOne, {
- attrs: {
+ props: {
target: '.other-target',
fit: true
}
@@ -245,7 +245,7 @@ describe('Menu API', () => {
it('should show a menu that not matches the full with of the target when fit is false', () => {
mount(WrapperOne, {
- attrs: {
+ props: {
target: '.other-target',
fit: false
}
@@ -266,7 +266,7 @@ describe('Menu API', () => {
describe('(prop): cover', () => {
it('should show a menu that overlays the target when using cover', () => {
mount(WrapperOne, {
- attrs: {
+ props: {
cover: true
}
})
@@ -279,7 +279,7 @@ describe('Menu API', () => {
it('should show a menu that overlays the target when using cover', () => {
mount(WrapperOne, {
- attrs: {
+ props: {
cover: true,
target: '.other-target'
}
@@ -293,7 +293,7 @@ describe('Menu API', () => {
it('should ignore self property when using cover', () => {
mount(WrapperOne, {
- attrs: {
+ props: {
cover: true,
self: 'center right',
target: '.other-target'
@@ -328,7 +328,7 @@ describe('Menu API', () => {
horizontalSelf.forEach((hS) => {
it(`should position Anchor(${ vA } ${ hA }) & Self(${ vS } ${ hS }) correctly`, () => {
mount(WrapperOne, {
- attrs: {
+ props: {
anchor: `${ vA } ${ hA }`,
self: `${ vS } ${ hS }`
}
@@ -357,7 +357,7 @@ describe('Menu API', () => {
verticalSelf.forEach((vS) => {
it(`should offset vertical position Anchor(${ vA } left) & Self(${ vS } left) correctly`, () => {
mount(WrapperOne, {
- attrs: {
+ props: {
anchor: `${ vA } left`,
self: `${ vS } left`,
offset: [ 0, 20 ]
@@ -378,7 +378,7 @@ describe('Menu API', () => {
horizontalSelf.forEach((hS) => {
it(`should offset horizontal position Anchor(top ${ hA }) & Self(top ${ hS }) correctly`, () => {
mount(WrapperOne, {
- attrs: {
+ props: {
anchor: `top ${ hA }`,
self: `top ${ hS }`,
offset: [ 20, 0 ]
@@ -399,7 +399,7 @@ describe('Menu API', () => {
describe('(prop): dark', () => {
it('should set the --q-dark color as background and white text color', () => {
mount(WrapperOne, {
- attrs: {
+ props: {
dark: true
}
})
@@ -414,7 +414,7 @@ describe('Menu API', () => {
describe('(prop): square', () => {
it('should not have border-radius when using this prop', () => {
mount(WrapperOne, {
- attrs: {
+ props: {
square: true
}
})
@@ -429,7 +429,7 @@ describe('Menu API', () => {
it('should specify a max-height when setting this prop', () => {
const maxHeight = '30px'
mount(WrapperOne, {
- attrs: {
+ props: {
maxHeight
}
})
@@ -444,7 +444,7 @@ describe('Menu API', () => {
it('should specify a max-width when setting this prop', () => {
const maxWidth = '30px'
mount(WrapperOne, {
- attrs: {
+ props: {
maxWidth
}
})
@@ -470,7 +470,7 @@ describe('Menu API', () => {
it('should emit @escape-key event when escape key is pressed', () => {
const fn = cy.stub()
mount(WrapperOne, {
- attrs: {
+ props: {
onEscapeKey: fn
}
})
@@ -493,7 +493,7 @@ describe('Menu API', () => {
it('should not emit @escape-key event when menu is persistent', () => {
const fn = cy.stub()
mount(WrapperOne, {
- attrs: {
+ props: {
onEscapeKey: fn,
persistent: true
}
@@ -520,7 +520,7 @@ describe('Menu API', () => {
describe('(method): updatePosition', () => {
it('should reposition the menu when it is no longer in correct position', () => {
mount(WrapperTwo, {
- attrs: {
+ props: {
anchor: 'bottom left',
self: 'bottom left'
}
@@ -564,7 +564,7 @@ describe('Menu API', () => {
describe('(method): focus', () => {
it('should focus the menu', () => {
mount(WrapperOne, {
- attrs: {
+ props: {
'no-focus': true
}
})
@@ -586,7 +586,7 @@ describe('Menu API', () => {
it('should focus the autofocus element inside the menu', () => {
mount(WrapperTwo, {
- attrs: {
+ props: {
'no-focus': true
}
})
diff --git a/ui/src/components/select/QSelect.js b/ui/src/components/select/QSelect.js
index 03b0f6853f8..555616087cd 100755
--- a/ui/src/components/select/QSelect.js
+++ b/ui/src/components/select/QSelect.js
@@ -127,7 +127,7 @@ export default createComponent({
emits: [
...useFieldEmits,
- 'add', 'remove', 'input-value',
+ 'add', 'remove', 'input-value', 'new-value',
'keyup', 'keypress', 'keydown',
'filter-abort'
],
diff --git a/ui/src/components/select/__tests__/QSelect.spec.js b/ui/src/components/select/__tests__/QSelect.spec.js
index 4550ae8ba69..43342b22841 100644
--- a/ui/src/components/select/__tests__/QSelect.spec.js
+++ b/ui/src/components/select/__tests__/QSelect.spec.js
@@ -1,7 +1,23 @@
/* eslint-disable no-unused-expressions */
import { mount } from '@cypress/vue'
-import { ref, h } from 'vue'
-import WrapperOne from './WrapperOne.vue'
+import { h, ref } from 'vue'
+import { vModelAdapter } from '../../../../test/cypress/helpers/v-model-adapter.js'
+import QSelect from '../QSelect.js'
+
+function getHostElement (extendedSelector = '') {
+ return cy.get(`.q-select ${ extendedSelector }`)
+}
+
+function mountQSelect (options = {}) {
+ if (!options.props?.modelValue) {
+ options.props = {
+ modelValue: null,
+ ...options.props ?? {}
+ }
+ }
+
+ return mount(QSelect, options)
+}
// QSelect does not set the `data-cy` attribute on the root element, but on the `.q-field__native` element
// This means we cannot use data-cy everywhere, but instead use a custom class `select-root` for this purpose
@@ -49,12 +65,12 @@ describe('QSelect API', () => {
describe('(prop): dropdown-icon', () => {
it('should use the dropdown-icon supplied', () => {
const icon = 'map'
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
dropdownIcon: icon
}
})
- cy.get('.select-root')
+ getHostElement()
.get(`div:contains(${ icon })`)
.should('exist')
})
@@ -62,21 +78,27 @@ describe('QSelect API', () => {
describe('(prop): use-input', () => {
it('should render an input inside the select', () => {
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
useInput: true
}
})
- cy.get('.select-root')
+ getHostElement()
.get('input')
.should('exist')
})
- it('should not render an input by default', () => {
- mount(WrapperOne)
- cy.get('.select-root')
+ it('should render an input, but it shouldn\'t be visible', () => {
+ mountQSelect()
+
+ getHostElement()
.get('input')
- .should('not.exist')
+ .should('not.be.visible')
+ })
+
+ it.skip('should not render an input by default', () => {
+ // Native input is now always rendered, due to having a target for autocomplete
+ // Refer to commit: https://github.com/quasarframework/quasar/commit/21a3af0dfe01bac0da617737562b599edee397a2
})
})
@@ -84,13 +106,13 @@ describe('QSelect API', () => {
it('should use an input-debounce of 500ms by default', () => {
const fn = cy.stub()
const text = 'Hello there'
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
useInput: true,
onFilter: fn
}
})
- cy.get('.select-root')
+ getHostElement()
.get('input')
.type(text)
.then(() => {
@@ -105,14 +127,14 @@ describe('QSelect API', () => {
it('should use a custom input-debounce', () => {
const fn = cy.stub()
const text = 'Hello there'
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
useInput: true,
onFilter: fn,
inputDebounce: 800
}
})
- cy.get('.select-root')
+ getHostElement()
.get('input')
.type(text)
.wait(500)
@@ -130,19 +152,19 @@ describe('QSelect API', () => {
describe('Category: content|behavior', () => {
describe('(prop): hide-dropdown-icon', () => {
it('should show the dropdown-icon when this property is not supplied', () => {
- mount(WrapperOne)
- cy.get('.select-root')
+ mountQSelect()
+ getHostElement()
.get('.q-icon')
.should('exist')
})
it('should hide the dropdown-icon when this property is true', () => {
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
hideDropdownIcon: true
}
})
- cy.get('.select-root')
+ getHostElement()
.get('.q-icon')
.should('not.exist')
})
@@ -152,21 +174,21 @@ describe('QSelect API', () => {
describe('Category: general', () => {
describe('(prop): tabindex', () => {
it('should have a default tabindex of 0', () => {
- mount(WrapperOne)
- cy.get('.select-root [tabindex="0"]')
+ mountQSelect()
+ getHostElement('[tabindex="0"]')
.should('exist')
})
it('should set the tabindex to the supplied value', () => {
const tabindex = 2
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
tabindex
}
})
- cy.get(`.select-root [tabindex="${ tabindex }"]`)
+ getHostElement(`[tabindex="${ tabindex }"]`)
.should('exist')
- cy.get('.select-root [tabindex="0"]')
+ getHostElement('[tabindex="0"]')
.should('not.exist')
})
})
@@ -176,13 +198,13 @@ describe('QSelect API', () => {
describe('(prop): model-value', () => {
it('should have the option selected passed in the model-value', () => {
const modelValue = 'Option 1'
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
modelValue,
options: [ 'Option 1', 'Option 2', 'Option 3' ]
}
})
- cy.get('.select-root')
+ getHostElement()
.should('include.text', modelValue)
})
})
@@ -190,14 +212,14 @@ describe('QSelect API', () => {
describe('(prop): emit-value', () => {
it('should emit the value under the value key, if options are objects', () => {
const fn = cy.stub()
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
emitValue: true,
'onUpdate:modelValue': fn,
options: [ { label: 'Option 1', value: 1 }, { label: 'Option 2', value: 2 } ]
}
})
- cy.get('.select-root')
+ getHostElement()
.click()
cy.get('.q-menu')
.contains('Option 1')
@@ -210,13 +232,13 @@ describe('QSelect API', () => {
it('should emit the whole object by default if options are objects', () => {
const fn = cy.stub()
const options = [ { label: 'Option 1', value: 1 }, { label: 'Option 2', value: 2 } ]
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
'onUpdate:modelValue': fn,
options
}
})
- cy.get('.select-root')
+ getHostElement()
.click()
cy.get('.q-menu')
.contains('Option 1')
@@ -233,58 +255,60 @@ describe('QSelect API', () => {
it('should select only one option by default', () => {
const options = [ 'Option 1', 'Option 2' ]
const model = ref(null)
- mount(WrapperOne, {
- attrs: {
- modelValue: model,
- 'onUpdate:modelValue': (val) => {
- model.value = val
- },
+ mountQSelect({
+ props: {
+ ...vModelAdapter(model),
options
}
})
- cy.get('.select-root')
- .click()
- cy.get('.q-menu')
- .contains('Option 1')
- .click()
- .then(() => {
- expect(model.value).to.equal(options[ 0 ])
- })
- cy.get('.q-menu')
- .contains('Option 2')
- .click()
- .then(() => {
- expect(model.value).to.equal(options[ 1 ])
- })
+
+ getHostElement().click()
+ cy.withinSelectMenu(() => {
+ cy.contains('Option 1')
+ .click()
+ .then(() => {
+ expect(model.value).to.equal(options[ 0 ])
+ })
+ })
+
+ getHostElement().click()
+ cy.withinSelectMenu(() => {
+ cy.contains('Option 2')
+ .click()
+ .then(() => {
+ expect(model.value).to.equal(options[ 1 ])
+ })
+ })
})
it('should select multiple options if multiple is true', () => {
const options = [ 'Option 1', 'Option 2' ]
const model = ref([])
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
+ ...vModelAdapter(model),
multiple: true,
- modelValue: model,
- 'onUpdate:modelValue': (val) => {
- model.value = val
- },
options
}
})
- cy.get('.select-root')
- .click()
- cy.get('.q-menu')
- .contains('Option 1')
- .click()
- .then(() => {
- expect(model.value).to.eql([ options[ 0 ] ])
- })
- cy.get('.q-menu')
- .contains('Option 2')
- .click()
- .then(() => {
- expect(model.value).to.eql(options)
- })
+
+ getHostElement().click()
+ cy.withinSelectMenu({
+ persistent: true,
+ fn: () => {
+ cy.contains('Option 1')
+ .click()
+ .then(() => {
+ expect(model.value).to.eql([ options[ 0 ] ])
+ })
+
+ cy.contains('Option 2')
+ .click()
+ .then(() => {
+ expect(model.value).to.eql(options)
+ })
+ }
+ })
})
})
})
@@ -293,12 +317,12 @@ describe('QSelect API', () => {
describe('(prop): options', () => {
it('should show each option when opening the dropdown', () => {
const options = [ 'Option 1', 'Option 2', 'Option 3', 'Option 4' ]
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
options
}
})
- cy.get('.select-root')
+ getHostElement()
.click()
cy.get('.q-menu')
.children()
@@ -313,17 +337,14 @@ describe('QSelect API', () => {
it('should use the value key as option-value by default', () => {
const options = [ { label: 'Option one', value: 1 }, { label: 'Option two', value: 2 } ]
const model = ref(null)
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
+ ...vModelAdapter(model),
options,
- emitValue: true,
- modelValue: model,
- 'onUpdate:modelValue': (val) => {
- model.value = val
- }
+ emitValue: true
}
})
- cy.get('.select-root')
+ getHostElement()
.click()
cy.get('.q-menu')
.contains(options[ 0 ].label)
@@ -336,18 +357,15 @@ describe('QSelect API', () => {
it('should use a custom key supplied by option-value', () => {
const options = [ { label: 'Option one', test: 1 }, { label: 'Option two', test: 2 } ]
const model = ref(null)
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
+ ...vModelAdapter(model),
options,
emitValue: true,
- optionValue: 'test',
- modelValue: model,
- 'onUpdate:modelValue': (val) => {
- model.value = val
- }
+ optionValue: 'test'
}
})
- cy.get('.select-root')
+ getHostElement()
.click()
cy.get('.q-menu')
.contains(options[ 0 ].label)
@@ -360,18 +378,15 @@ describe('QSelect API', () => {
it('should accept a function as option-value', () => {
const options = [ { label: 'Option one', test: 1 }, { label: 'Option two', test: 2 } ]
const model = ref(null)
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
+ ...vModelAdapter(model),
options,
emitValue: true,
- optionValue: (val) => val.test,
- modelValue: model,
- 'onUpdate:modelValue': (val) => {
- model.value = val
- }
+ optionValue: (val) => val.test
}
})
- cy.get('.select-root')
+ getHostElement()
.click()
cy.get('.q-menu')
.contains(options[ 0 ].label)
@@ -385,12 +400,12 @@ describe('QSelect API', () => {
describe('(prop): option-label', () => {
it('should use the "label" key by default as option-label', () => {
const options = [ { label: 'Option one', value: 1 }, { label: 'Option two', value: 2 } ]
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
options
}
})
- cy.get('.select-root')
+ getHostElement()
.click()
cy.get('.q-menu')
.children()
@@ -400,13 +415,13 @@ describe('QSelect API', () => {
it('should use the key supplied by option-label', () => {
const options = [ { test: 'Option one', value: 1 }, { test: 'Option two', value: 2 } ]
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
options,
optionLabel: 'test'
}
})
- cy.get('.select-root')
+ getHostElement()
.click()
cy.get('.q-menu')
.children()
@@ -416,13 +431,13 @@ describe('QSelect API', () => {
it('should accept a function as option-label', () => {
const options = [ { test: 'Option one', value: 1 }, { test: 'Option two', value: 2 } ]
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
options,
optionLabel: (item) => (item === null ? 'Null' : item.test)
}
})
- cy.get('.select-root')
+ getHostElement()
.click()
cy.get('.q-menu')
.children()
@@ -433,12 +448,12 @@ describe('QSelect API', () => {
describe('(prop): option-disable', () => {
it('should use the "disable" key by default as option-disable', () => {
const options = [ { label: 'Option one', value: 1, disable: true }, { label: 'Option two', value: 2, disable: true } ]
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
options
}
})
- cy.get('.select-root')
+ getHostElement()
.click()
cy.get('.q-menu')
.get('[role="option"][aria-disabled="true"]')
@@ -447,13 +462,13 @@ describe('QSelect API', () => {
it('should use the key supplied by option-disable', () => {
const options = [ { label: 'Option one', value: 1, test: true }, { label: 'Option two', value: 2, disable: true } ]
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
options,
optionDisable: 'test'
}
})
- cy.get('.select-root')
+ getHostElement()
.click()
cy.get('.q-menu')
.get('[role="option"][aria-disabled="true"]')
@@ -463,13 +478,13 @@ describe('QSelect API', () => {
it('should accept a function as option-disable', () => {
const options = [ { label: 'Option one', value: 1, test: true }, { label: 'Option two', value: 2, disable: true } ]
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
options,
optionDisable: (item) => (item === null ? true : item.test)
}
})
- cy.get('.select-root')
+ getHostElement()
.click()
cy.get('.q-menu')
.get('[role="option"][aria-disabled="true"]')
@@ -481,13 +496,13 @@ describe('QSelect API', () => {
describe('(prop): options-dense', () => {
it('should show options list dense', () => {
const options = [ 'Option 1', 'Option 2', 'Option 3', 'Option 4' ]
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
options,
optionsDense: true
}
})
- cy.get('.select-root')
+ getHostElement()
.click()
cy.get('.q-menu')
.get('.q-item')
@@ -498,13 +513,13 @@ describe('QSelect API', () => {
describe('(prop): options-dark', () => {
it('should show options list in dark mode', () => {
const options = [ 'Option 1', 'Option 2', 'Option 3', 'Option 4' ]
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
options,
optionsDark: true
}
})
- cy.get('.select-root')
+ getHostElement()
.click()
cy.get('.q-menu')
.get('.q-item')
@@ -515,14 +530,14 @@ describe('QSelect API', () => {
describe('(prop): options-selected-class', () => {
it('should have text-{color} applied as selected by default', () => {
const options = [ 'Option 1', 'Option 2', 'Option 3', 'Option 4' ]
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
options,
modelValue: 'Option 1',
color: 'orange'
}
})
- cy.get('.select-root')
+ getHostElement()
.click()
cy.get('.q-menu')
.contains('[role="option"]', options[ 0 ])
@@ -531,15 +546,15 @@ describe('QSelect API', () => {
it('should not have default active class when passed option is empty', () => {
const options = [ 'Option 1', 'Option 2', 'Option 3', 'Option 4' ]
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
options,
modelValue: 'Option 1',
optionsSelectedClass: '',
color: 'orange'
}
})
- cy.get('.select-root')
+ getHostElement()
.click()
cy.get('.q-menu')
.contains('[role="option"]', options[ 0 ])
@@ -548,15 +563,15 @@ describe('QSelect API', () => {
it('should have class name supplied by options-selected-class on active item', () => {
const options = [ 'Option 1', 'Option 2', 'Option 3', 'Option 4' ]
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
options,
modelValue: 'Option 1',
optionsSelectedClass: 'test-class',
color: 'orange'
}
})
- cy.get('.select-root')
+ getHostElement()
.click()
cy.get('.q-menu')
.contains('[role="option"]', options[ 0 ])
@@ -572,12 +587,12 @@ describe('QSelect API', () => {
describe('(prop): options-html', () => {
it('should not render options with html by default', () => {
const options = [ 'Option 1', 'Option 2' ]
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
options
}
})
- cy.get('.select-root')
+ getHostElement()
.click()
cy.get('.q-menu')
.contains('Option 1')
@@ -587,13 +602,13 @@ describe('QSelect API', () => {
it('should render options with html when options-html is true', () => {
const options = [ 'Option 1', 'Option 2' ]
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
options,
optionsHtml: true
}
})
- cy.get('.select-root')
+ getHostElement()
.click()
cy.get('.q-menu')
.contains('Option 1')
@@ -605,27 +620,27 @@ describe('QSelect API', () => {
describe('(prop): options-cover', () => {
it('should make the popup menu cover the select', (done) => {
const options = [ 'Option 1', 'Option 2', 'Option 3', 'Option 4' ]
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
options,
optionsCover: true
}
})
- cy.get('.select-root')
+ getHostElement()
.click()
.isNotActionable(done)
})
it('should not make the popup menu cover the select when use-input is used', () => {
const options = [ 'Option 1', 'Option 2', 'Option 3', 'Option 4' ]
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
options,
optionsCover: true,
useInput: true
}
})
- cy.get('.select-root')
+ getHostElement()
.click()
.click({ timeout: 100 })
})
@@ -634,14 +649,14 @@ describe('QSelect API', () => {
describe('(prop): menu-shrink', () => {
it('should shrink the menu', () => {
const options = [ '1', '2', '3', '4' ]
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
options,
menuShrink: true
}
})
let selectWidth = 0
- cy.get('.select-root')
+ getHostElement()
.then(($el) => {
selectWidth = $el[ 0 ].clientWidth
})
@@ -656,26 +671,26 @@ describe('QSelect API', () => {
describe('(prop): map-options', () => {
it('should display the label of the selected value instead of the value itself', () => {
const options = [ { label: 'Option one', value: 1 }, { label: 'Option two', value: 2 } ]
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
options,
modelValue: 1,
mapOptions: true
}
})
- cy.get('.select-root')
+ getHostElement()
.contains(options[ 0 ].label)
})
it('should display the selected value as string by default', () => {
const options = [ { label: 'Option one', value: 1 }, { label: 'Option two', value: 2 } ]
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
options,
modelValue: 1
}
})
- cy.get('.select-root')
+ getHostElement()
.contains(options[ 0 ].value)
})
})
@@ -699,37 +714,37 @@ describe('QSelect API', () => {
describe('(prop): display-value', () => {
it('should override the default selection string', () => {
const options = [ { label: 'Option one', value: 1 }, { label: 'Option two', value: 2 } ]
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
options,
modelValue: 1,
displayValue: 'Test'
}
})
- cy.get('.select-root')
+ getHostElement()
.should('not.contain', options[ 0 ].value)
.should('contain', 'Test')
})
it('should not override the default selection string when using `use-chips`', () => {
const options = [ { label: 'Option one', value: 1 }, { label: 'Option two', value: 2 } ]
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
options,
modelValue: 1,
displayValue: 'Test',
useChips: true
}
})
- cy.get('.select-root')
+ getHostElement()
.should('contain', options[ 0 ].value)
.should('not.contain', 'Test')
})
it('should not override the default selection string when using `selected` slot', () => {
const options = [ { label: 'Option one', value: 1 }, { label: 'Option two', value: 2 } ]
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
options,
modelValue: 1,
displayValue: 'Test'
@@ -738,7 +753,7 @@ describe('QSelect API', () => {
selected: () => 'Hello there'
}
})
- cy.get('.select-root')
+ getHostElement()
.should('not.contain', options[ 0 ].value)
.should('not.contain', 'Test')
.should('contain', 'Hello there')
@@ -748,14 +763,14 @@ describe('QSelect API', () => {
describe('(prop): display-value-html', () => {
it('should render the selected option as html', () => {
const options = [ 'Option 1', 'Option 2' ]
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
options,
modelValue: options[ 0 ],
displayValueHtml: true
}
})
- cy.get('.select-root')
+ getHostElement()
.contains('Option 1')
.should('have.color', 'red')
.should('have.css', 'font-weight', '700')
@@ -764,8 +779,8 @@ describe('QSelect API', () => {
it('should not render the selected option as html when using `selected` slot', () => {
const html = 'Option 1'
const options = [ 'Option 1', 'Option 2' ]
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
options,
modelValue: options[ 0 ],
displayValueHtml: true
@@ -774,15 +789,15 @@ describe('QSelect API', () => {
selected: () => html
}
})
- cy.get('.select-root')
+ getHostElement()
.contains(html)
})
it('should not render the selected option as html when using `selected-item` slot', () => {
const html = 'Option 1'
const options = [ 'Option 1', 'Option 2' ]
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
options,
modelValue: options[ 0 ],
displayValueHtml: true
@@ -791,7 +806,7 @@ describe('QSelect API', () => {
'selected-item': () => html
}
})
- cy.get('.select-root')
+ getHostElement()
.contains(html)
})
})
@@ -799,22 +814,22 @@ describe('QSelect API', () => {
describe('(prop): hide-selected', () => {
it('should not show the selected value', () => {
const options = [ 'Option 1', 'Option 2' ]
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
options,
modelValue: options[ 0 ],
hideSelected: true
}
})
- cy.get('.select-root')
+ getHostElement()
.should('not.contain', options[ 0 ])
})
it('should set the value on the underlying input when using hide-selected', () => {
// Todo: it its not really clear from the docs that you need to use `useInput` and `fillInput` together with this prop to achieve this
const options = [ 'Option 1', 'Option 2' ]
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
options,
modelValue: options[ 0 ],
hideSelected: true,
@@ -822,7 +837,7 @@ describe('QSelect API', () => {
useInput: true
}
})
- cy.get('.select-root')
+ getHostElement()
.get('input')
.should('have.value', options[ 0 ])
})
@@ -832,25 +847,22 @@ describe('QSelect API', () => {
it('should allow a maximum number of selections', () => {
const max = 3
const options = [ '1', '2', '3', '4', '5' ]
- const modelValue = ref([])
- mount(WrapperOne, {
- attrs: {
+ const model = ref([])
+ mountQSelect({
+ props: {
+ ...vModelAdapter(model),
options,
- modelValue,
maxValues: max,
- 'onUpdate:modelValue': (val) => {
- modelValue.value = val
- },
multiple: true
}
})
- cy.get('.select-root')
+ getHostElement()
.click()
cy.get('.q-menu')
.get('[role="option"]')
.click({ multiple: true })
.then(() => {
- expect(modelValue.value.length).to.equal(max)
+ expect(model.value.length).to.equal(max)
})
})
})
@@ -858,14 +870,14 @@ describe('QSelect API', () => {
describe('(prop): use-chips', () => {
it('should use QChips to show the selected value', () => {
const options = [ 'Option 1', 'Option 2' ]
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
options,
modelValue: options[ 0 ],
useChips: true
}
})
- cy.get('.select-root')
+ getHostElement()
.get('.q-chip')
.should('contain', options[ 0 ])
})
@@ -876,13 +888,13 @@ describe('QSelect API', () => {
describe('(prop): popup-content-class', () => {
it('should apply the class to the popup element', () => {
const className = 'test-class'
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
options: [ '1', '2 ' ],
popupContentClass: className
}
})
- cy.get('.select-root')
+ getHostElement()
.click()
cy.get('.q-menu')
.should('have.class', className)
@@ -892,13 +904,13 @@ describe('QSelect API', () => {
describe('(prop): popup-content-style', () => {
it('should apply the style definitions to the popup element', () => {
const style = 'background: red;'
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
options: [ '1', '2 ' ],
popupContentStyle: style
}
})
- cy.get('.select-root')
+ getHostElement()
.click()
cy.get('.q-menu')
.should('have.backgroundColor', 'red')
@@ -908,13 +920,13 @@ describe('QSelect API', () => {
describe('(prop): input-class', () => {
it('should apply a class to the input element when using `useInput`', () => {
const className = 'test-class'
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
useInput: true,
inputClass: className
}
})
- cy.get('.select-root')
+ getHostElement()
.get('input')
.should('have.class', className)
})
@@ -923,13 +935,13 @@ describe('QSelect API', () => {
describe('(prop): input-style', () => {
it('should apply a style to the input element when using `useInput`', () => {
const style = 'font-size: 30px'
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
useInput: true,
inputStyle: style
}
})
- cy.get('.select-root')
+ getHostElement()
.get('input')
.should('have.css', 'font-size', '30px')
})
@@ -942,8 +954,8 @@ describe('QSelect API', () => {
it('should display when something is selected', () => {
const selectedString = 'Test slot selected'
const options = [ 'Option 1', 'Option 2' ]
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
options,
modelValue: options[ 0 ]
},
@@ -951,7 +963,7 @@ describe('QSelect API', () => {
selected: () => selectedString
}
})
- cy.get('.select-root')
+ getHostElement()
.should('contain', selectedString)
})
})
@@ -959,44 +971,44 @@ describe('QSelect API', () => {
describe('(slot): loading', () => {
it('should display when element is loading', () => {
const loadingString = 'Test slot loading'
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
loading: true
},
slots: {
loading: () => loadingString
}
})
- cy.get('.select-root')
+ getHostElement()
.should('contain', loadingString)
})
it('should not display when element is loading', () => {
const loadingString = 'Test slot loading'
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
loading: false
},
slots: {
loading: () => loadingString
}
})
- cy.get('.select-root')
+ getHostElement()
.should('not.contain', loadingString)
})
})
describe('(slot): before-options', () => {
it('should display the slot content before the options', () => {
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
options: [ '1', '2', '3' ]
},
slots: {
'before-options': () => h('div', { class: 'dummyClass' }, 'Hello')
}
})
- cy.get('.select-root')
+ getHostElement()
.click()
cy.get('.q-menu')
.children().first()
@@ -1006,15 +1018,15 @@ describe('QSelect API', () => {
describe('(slot): after-options', () => {
it('should display the slot content after the options', () => {
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
options: [ '1', '2', '3' ]
},
slots: {
'after-options': () => h('div', { class: 'dummyClass' }, 'Hello')
}
})
- cy.get('.select-root')
+ getHostElement()
.click()
cy.get('.q-menu')
.children().last()
@@ -1025,15 +1037,15 @@ describe('QSelect API', () => {
describe('(slot): no-option', () => {
it('should display the slot content when there are no options', () => {
const compareString = 'No options :('
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
options: [ ]
},
slots: {
'no-option': () => compareString
}
})
- cy.get('.select-root')
+ getHostElement()
.click()
cy.get('.q-menu')
.should('contain', compareString)
@@ -1041,8 +1053,8 @@ describe('QSelect API', () => {
it('should pass the inputValue to the slot scope', () => {
const compareString = 'No options :('
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
options: [ ],
useInput: true
},
@@ -1050,7 +1062,7 @@ describe('QSelect API', () => {
'no-option': (scope) => compareString + scope.inputValue
}
})
- cy.get('.select-root')
+ getHostElement()
.click()
.type('Hello')
cy.get('.q-menu')
@@ -1059,15 +1071,15 @@ describe('QSelect API', () => {
it('should not display the slot content when there are options', () => {
const compareString = 'No options :('
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
options: [ '1', '2', '3' ]
},
slots: {
'no-option': () => compareString
}
})
- cy.get('.select-root')
+ getHostElement()
.click()
cy.get('.q-menu')
.should('not.contain', compareString)
@@ -1077,8 +1089,8 @@ describe('QSelect API', () => {
describe('(slot): selected-item', () => {
it('should override the default selection slot', () => {
const options = [ { label: 'Option one', value: 1 }, { label: 'Option two', value: 2 } ]
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
options,
modelValue: 1
},
@@ -1086,15 +1098,15 @@ describe('QSelect API', () => {
'selected-item': () => 'Test'
}
})
- cy.get('.select-root')
+ getHostElement()
.should('not.contain', options[ 0 ].value)
.should('contain', 'Test')
})
it('should pass the selected option index to the slot scope', () => {
const options = [ { label: 'Option one', value: 1 }, { label: 'Option two', value: 2 } ]
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
options,
modelValue: 1
},
@@ -1102,14 +1114,14 @@ describe('QSelect API', () => {
'selected-item': (scope) => 'Test' + scope.index
}
})
- cy.get('.select-root')
+ getHostElement()
.should('contain', 'Test0')
})
it('should pass the selected option value to the slot scope', () => {
const options = [ { label: 'Option one', value: 1 }, { label: 'Option two', value: 2 } ]
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
options,
modelValue: 1
},
@@ -1117,29 +1129,26 @@ describe('QSelect API', () => {
'selected-item': (scope) => 'Test' + scope.opt
}
})
- cy.get('.select-root')
+ getHostElement()
.should('contain', 'Test1')
})
it('should pass a removeAtIndex function to the slot scope', () => {
const options = [ { label: 'Option one', value: 1 }, { label: 'Option two', value: 2 } ]
const model = ref(1)
- mount(WrapperOne, {
- attrs: {
- options,
- modelValue: model,
- 'onUpdate:modelValue': (val) => {
- model.value = val
- }
+ mountQSelect({
+ props: {
+ ...vModelAdapter(model),
+ options
},
slots: {
'selected-item': (scope) => h('button', { class: 'remove', onClick: () => scope.removeAtIndex(scope.index) }, 'Remove')
}
})
- cy.get('.select-root')
+ getHostElement()
.get('button.remove')
.click()
- cy.get('.select-root')
+ getHostElement()
.get('button.remove')
.should('not.exist')
})
@@ -1147,23 +1156,20 @@ describe('QSelect API', () => {
it('should pass a toggleOption function to the slot scope', () => {
const options = [ { label: 'Option one', value: 1 }, { label: 'Option two', value: 2 } ]
const model = ref(1)
- mount(WrapperOne, {
- attrs: {
- options,
- modelValue: model,
- 'onUpdate:modelValue': (val) => {
- model.value = val
- }
+ mountQSelect({
+ props: {
+ ...vModelAdapter(model),
+ options
},
slots: {
'selected-item': (scope) => h('button', { class: 'toggle', onClick: () => scope.toggleOption(2) }, 'Toggle' + scope.opt)
}
})
- cy.get('.select-root')
+ getHostElement()
.get('button.toggle')
.should('contain', 'Toggle1')
.click()
- cy.get('.select-root')
+ getHostElement()
.get('button.toggle')
.should('contain', 'Toggle2')
})
@@ -1172,15 +1178,15 @@ describe('QSelect API', () => {
describe('(slot): option', () => {
it('should render a list of the provided slot as options', () => {
const options = [ '1', '2', '3' ]
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
options
},
slots: {
option: (scope) => h('div', { class: 'custom-option' }, scope.opt)
}
})
- cy.get('.select-root')
+ getHostElement()
.click()
cy.get('.q-menu')
.get('.custom-option')
@@ -1189,8 +1195,8 @@ describe('QSelect API', () => {
it('should have a selected property in the scope', () => {
const options = [ '1', '2', '3' ]
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
modelValue: '1',
options
},
@@ -1198,7 +1204,7 @@ describe('QSelect API', () => {
option: (scope) => h('div', { class: `custom-option-${ scope.selected }` }, scope.opt + scope.selected)
}
})
- cy.get('.select-root')
+ getHostElement()
.click()
cy.get('.q-menu')
.get('.custom-option-true')
@@ -1212,8 +1218,8 @@ describe('QSelect API', () => {
describe('(event): update:model-value', () => {
it('should emit event when model value changes', () => {
const fn = cy.stub()
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
options: [ '1', '2', '3' ],
modelValue: null,
'onUpdate:modelValue': fn
@@ -1221,7 +1227,7 @@ describe('QSelect API', () => {
})
expect(fn).not.to.be.called
- cy.get('.select-root')
+ getHostElement()
.click()
cy.get('.q-menu')
.get('[role="option"]')
@@ -1236,8 +1242,8 @@ describe('QSelect API', () => {
describe('(event): input-value', () => {
it('should emit event when text input changes', () => {
const fn = cy.stub()
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
modelValue: null,
onInputValue: fn,
useInput: true
@@ -1245,7 +1251,7 @@ describe('QSelect API', () => {
})
expect(fn).not.to.be.called
- cy.get('.select-root')
+ getHostElement()
.get('input')
.type('h')
.then(() => {
@@ -1258,20 +1264,17 @@ describe('QSelect API', () => {
it('should emit event when a selected item is removed from selection', () => {
const fn = cy.stub()
const model = ref([ '2', '3' ])
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
+ ...vModelAdapter(model),
onRemove: fn,
multiple: true,
- modelValue: model,
- 'onUpdate:modelValue': (val) => {
- model.value = val
- },
options: [ '1', '2', '3' ]
}
})
expect(fn).not.to.be.called
- cy.get('.select-root')
+ getHostElement()
.click()
cy.get('.q-menu')
.get('[role="option"]')
@@ -1295,20 +1298,17 @@ describe('QSelect API', () => {
it('should emit event when an option is added to the selection', () => {
const fn = cy.stub()
const model = ref([ '2' ])
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
+ ...vModelAdapter(model),
onAdd: fn,
multiple: true,
- modelValue: model,
- 'onUpdate:modelValue': (val) => {
- model.value = val
- },
options: [ '1', '2', '3' ]
}
})
expect(fn).not.to.be.called
- cy.get('.select-root')
+ getHostElement()
.click()
cy.get('.q-menu')
.get('[role="option"]')
@@ -1325,21 +1325,18 @@ describe('QSelect API', () => {
it('should emit event when something is typed into the input field and enter is pressed', () => {
const fn = cy.stub()
const model = ref([ '2' ])
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
+ ...vModelAdapter(model),
onNewValue: fn,
multiple: true,
useInput: true,
- modelValue: model,
- 'onUpdate:modelValue': (val) => {
- model.value = val
- },
hideDropdownIcon: true
}
})
expect(fn).not.to.be.called
- cy.get('.select-root')
+ getHostElement()
.get('input')
.type('100')
.then(() => {
@@ -1353,22 +1350,19 @@ describe('QSelect API', () => {
it('should add the value to the model when the doneFn is called', () => {
const model = ref([ '2' ])
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
+ ...vModelAdapter(model),
onNewValue: (val, doneFn) => {
doneFn(val)
},
multiple: true,
useInput: true,
- modelValue: model,
- 'onUpdate:modelValue': (val) => {
- model.value = val
- },
hideDropdownIcon: true
}
})
- cy.get('.select-root')
+ getHostElement()
.get('input')
.type('100')
.type('{enter}')
@@ -1381,8 +1375,8 @@ describe('QSelect API', () => {
describe('(event): filter', () => {
it('should emit event when something is typed into the input field', () => {
const fn = cy.stub()
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
onFilter: fn,
useInput: true,
inputDebounce: 0
@@ -1390,7 +1384,7 @@ describe('QSelect API', () => {
})
expect(fn).not.to.be.called
- cy.get('.select-root')
+ getHostElement()
.get('input')
.type('h')
.then(() => {
@@ -1403,8 +1397,8 @@ describe('QSelect API', () => {
it('should emit event when the the filterFn has not called the doneFn yet and a new filter is requested', () => {
const fn = cy.stub()
const filterFn = cy.stub()
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
onFilter: filterFn,
onFilterAbort: fn,
useInput: true,
@@ -1413,7 +1407,7 @@ describe('QSelect API', () => {
})
expect(fn).not.to.be.called
- cy.get('.select-root')
+ getHostElement()
.get('input')
.click()
.then(() => {
@@ -1428,8 +1422,8 @@ describe('QSelect API', () => {
it('should not emit event when the filter has called its doneFn', () => {
const fn = cy.stub()
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
onFilter: (val, doneFn) => {
doneFn()
},
@@ -1440,7 +1434,7 @@ describe('QSelect API', () => {
})
expect(fn).not.to.be.called
- cy.get('.select-root')
+ getHostElement()
.get('input')
.click()
.then(() => {
@@ -1456,15 +1450,15 @@ describe('QSelect API', () => {
describe('(event): popup-show', () => {
it('should emit event when the options are shown', () => {
const fn = cy.stub()
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
onPopupShow: fn,
options: [ '1', '2', '3' ]
}
})
expect(fn).not.to.be.called
- cy.get('.select-root')
+ getHostElement()
.click()
.then(() => {
expect(fn).to.be.called
@@ -1475,15 +1469,15 @@ describe('QSelect API', () => {
describe('(event): popup-hide', () => {
it('should emit event when the options are hidden', () => {
const fn = cy.stub()
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
onPopupHide: fn,
options: [ '1', '2', '3' ]
}
})
expect(fn).not.to.be.called
- cy.get('.select-root')
+ getHostElement()
.click()
.then(() => {
expect(fn).not.to.be.called
@@ -1508,16 +1502,16 @@ describe('QSelect API', () => {
describe('Methods', () => {
describe('(method): focus', () => {
it('should focus the component', () => {
- mount(WrapperOne)
+ mountQSelect()
- cy.dataCy('select')
+ getHostElement()
.get('[tabindex="0"]')
.should('not.have.focus')
- cy.dataCy('select')
+ getHostElement()
.then(() => {
- Cypress.vueWrapper.vm.compRef.focus()
+ Cypress.vueWrapper.vm.focus()
})
- cy.dataCy('select')
+ getHostElement()
.get('[tabindex="0"]')
.should('have.focus')
})
@@ -1525,8 +1519,8 @@ describe('QSelect API', () => {
describe('(method): showPopup', () => {
it('should open the popup and focus the component', () => {
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
options: [ '1', '2' ]
}
})
@@ -1534,11 +1528,11 @@ describe('QSelect API', () => {
cy.get('.q-menu')
.should('not.exist')
.then(() => {
- Cypress.vueWrapper.vm.compRef.showPopup()
+ Cypress.vueWrapper.vm.showPopup()
})
cy.get('.q-menu')
.should('be.visible')
- cy.dataCy('select')
+ getHostElement()
.get('[tabindex="0"]')
.should('have.focus')
})
@@ -1546,18 +1540,18 @@ describe('QSelect API', () => {
describe('(method): hidePopup', () => {
it('should hide the popup', () => {
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
options: [ '1', '2' ]
}
})
- cy.get('.select-root')
+ getHostElement()
.click()
cy.get('.q-menu')
.should('be.visible')
.then(() => {
- Cypress.vueWrapper.vm.compRef.hidePopup()
+ Cypress.vueWrapper.vm.hidePopup()
})
cy.get('.q-menu')
.should('not.exist')
@@ -1568,19 +1562,16 @@ describe('QSelect API', () => {
it('should remove a selected option at the correct index', () => {
const options = [ '1', '2', '3', '4' ]
const model = ref([ '1', '2', '4' ])
- mount(WrapperOne, {
- attrs: {
- modelValue: model,
- 'onUpdate:modelValue': (val) => {
- model.value = val
- },
+ mountQSelect({
+ props: {
+ ...vModelAdapter(model),
multiple: true,
options
}
})
.then(() => {
expect(model.value.includes('4')).to.be.true
- Cypress.vueWrapper.vm.compRef.removeAtIndex(2)
+ Cypress.vueWrapper.vm.removeAtIndex(2)
expect(model.value.includes('4')).to.be.false
})
})
@@ -1589,38 +1580,32 @@ describe('QSelect API', () => {
describe('(method): add', () => {
it('should add a selected option', () => {
const model = ref([ '1', '2' ])
- mount(WrapperOne, {
- attrs: {
- modelValue: model,
- 'onUpdate:modelValue': (val) => {
- model.value = val
- },
+ mountQSelect({
+ props: {
+ ...vModelAdapter(model),
multiple: true
}
})
.then(() => {
expect(model.value.includes('100')).to.be.false
- Cypress.vueWrapper.vm.compRef.add('100')
+ Cypress.vueWrapper.vm.add('100')
expect(model.value.includes('100')).to.be.true
})
})
it('should not add a duplicate option when unique is true', () => {
const model = ref([ '1', '2' ])
- mount(WrapperOne, {
- attrs: {
- modelValue: model,
- 'onUpdate:modelValue': (val) => {
- model.value = val
- },
+ mountQSelect({
+ props: {
+ ...vModelAdapter(model),
multiple: true
}
})
.then(() => {
expect(model.value.length).to.be.equal(2)
- Cypress.vueWrapper.vm.compRef.add('2', true)
+ Cypress.vueWrapper.vm.add('2', true)
expect(model.value.length).to.be.equal(2)
- Cypress.vueWrapper.vm.compRef.add('2')
+ Cypress.vueWrapper.vm.add('2')
expect(model.value.length).to.be.equal(3)
})
})
@@ -1629,24 +1614,21 @@ describe('QSelect API', () => {
describe('(method): toggleOption', () => {
it('should toggle an option', () => {
const model = ref([ '1', '2' ])
- mount(WrapperOne, {
- attrs: {
- modelValue: model,
- 'onUpdate:modelValue': (val) => {
- model.value = val
- },
+ mountQSelect({
+ props: {
+ ...vModelAdapter(model),
multiple: true
}
})
.then(() => {
expect(model.value.length).to.be.equal(2)
- Cypress.vueWrapper.vm.compRef.toggleOption('2')
+ Cypress.vueWrapper.vm.toggleOption('2')
expect(model.value.length).to.be.equal(1)
})
// When not using this wait this test will succeed on `open-ct` but fail on `run-ct`
.wait(50)
.then(() => {
- Cypress.vueWrapper.vm.compRef.toggleOption('2')
+ Cypress.vueWrapper.vm.toggleOption('2')
expect(model.value.length).to.be.equal(2)
})
})
@@ -1655,25 +1637,22 @@ describe('QSelect API', () => {
// should this be consistent? E.g. use `true` as argument when multiple is true by default but make sure it can be overridden.
it('should close the menu and clear the filter', () => {
const model = ref('1')
- mount(WrapperOne, {
- attrs: {
- modelValue: model,
- 'onUpdate:modelValue': (val) => {
- model.value = val
- },
+ mountQSelect({
+ props: {
+ ...vModelAdapter(model),
options: [ '1', '2' ],
useInput: true
}
})
- cy.get('.select-root')
+ getHostElement()
.click()
.get('input')
.type('h')
cy.get('.q-menu')
.should('be.visible')
.then(() => {
- Cypress.vueWrapper.vm.compRef.toggleOption('2')
+ Cypress.vueWrapper.vm.toggleOption('2')
})
cy.get('.q-menu')
.should('not.exist')
@@ -1683,25 +1662,22 @@ describe('QSelect API', () => {
it('should not close the menu and clear the filter when keepOpen is true', () => {
const model = ref('1')
- mount(WrapperOne, {
- attrs: {
- modelValue: model,
- 'onUpdate:modelValue': (val) => {
- model.value = val
- },
+ mountQSelect({
+ props: {
+ ...vModelAdapter(model),
options: [ '1', '2' ],
useInput: true
}
})
- cy.get('.select-root')
+ getHostElement()
.click()
.get('input')
.type('h')
cy.get('.q-menu')
.should('be.visible')
.then(() => {
- Cypress.vueWrapper.vm.compRef.toggleOption('2', true)
+ Cypress.vueWrapper.vm.toggleOption('2', true)
})
cy.get('.q-menu')
.should('be.visible')
@@ -1713,15 +1689,15 @@ describe('QSelect API', () => {
describe('(method): setOptionIndex', () => {
it('should set an option from the menu dropdown as focused', () => {
const options = [ '1', '2', '3', '4' ]
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
options
}
})
- cy.get('.select-root')
+ getHostElement()
.click()
.then(() => {
- Cypress.vueWrapper.vm.compRef.setOptionIndex(0)
+ Cypress.vueWrapper.vm.setOptionIndex(0)
})
.get('[role="option"]')
.first()
@@ -1732,21 +1708,21 @@ describe('QSelect API', () => {
describe('(method): moveOptionSelection', () => {
it('should move the optionSelection by some index offset', () => {
const options = [ '1', '2', '3', '4' ]
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
options
}
})
- cy.get('.select-root')
+ getHostElement()
.click()
.then(() => {
- Cypress.vueWrapper.vm.compRef.setOptionIndex(0)
+ Cypress.vueWrapper.vm.setOptionIndex(0)
})
.get('[role="option"]')
.first()
.should('have.class', 'q-manual-focusable--focused')
.then(() => {
- Cypress.vueWrapper.vm.compRef.moveOptionSelection(3)
+ Cypress.vueWrapper.vm.moveOptionSelection(3)
})
.get('[role="option"]')
.last()
@@ -1759,18 +1735,18 @@ describe('QSelect API', () => {
const options = [ '1', '2', '3', '4' ]
const fn = cy.stub()
const text = 'test'
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
options,
useInput: true,
onFilter: fn
}
})
- cy.get('.select-root')
+ getHostElement()
.click()
.then(() => {
expect(fn).not.to.be.calledWith(text)
- Cypress.vueWrapper.vm.compRef.filter(text)
+ Cypress.vueWrapper.vm.filter(text)
expect(fn).to.be.calledWith(text)
})
})
@@ -1787,18 +1763,18 @@ describe('QSelect API', () => {
const options = [ '1', '2', '3', '4' ]
const fn = cy.stub()
const text = 'test'
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
options,
useInput: true,
onFilter: fn
}
})
- cy.get('.select-root')
+ getHostElement()
.click()
.then(() => {
expect(fn).not.to.be.calledWith(text)
- Cypress.vueWrapper.vm.compRef.updateInputValue(text)
+ Cypress.vueWrapper.vm.updateInputValue(text)
expect(fn).to.be.calledWith(text)
})
.get('input')
@@ -1809,18 +1785,18 @@ describe('QSelect API', () => {
const options = [ '1', '2', '3', '4' ]
const fn = cy.stub()
const text = 'test'
- mount(WrapperOne, {
- attrs: {
+ mountQSelect({
+ props: {
options,
useInput: true,
onFilter: fn
}
})
- cy.get('.select-root')
+ getHostElement()
.click()
.then(() => {
expect(fn).not.to.be.calledWith(text)
- Cypress.vueWrapper.vm.compRef.updateInputValue(text, true)
+ Cypress.vueWrapper.vm.updateInputValue(text, true)
expect(fn).not.to.be.calledWith(text)
})
.get('input')
@@ -1831,17 +1807,17 @@ describe('QSelect API', () => {
describe('(method): isOptionSelected', () => {
it('should tell when an option is selected', () => {
const options = [ '1', '2', '3', '4' ]
- const model = ref([ '1', '2', '4' ])
- mount(WrapperOne, {
- attrs: {
- modelValue: model,
+ const modelValue = [ '1', '2', '4' ]
+ mountQSelect({
+ props: {
+ modelValue,
multiple: true,
options
}
})
.then(() => {
- expect(Cypress.vueWrapper.vm.compRef.isOptionSelected(options[ 0 ])).to.be.true
- expect(Cypress.vueWrapper.vm.compRef.isOptionSelected(options[ 2 ])).to.be.false
+ expect(Cypress.vueWrapper.vm.isOptionSelected(options[ 0 ])).to.be.true
+ expect(Cypress.vueWrapper.vm.isOptionSelected(options[ 2 ])).to.be.false
})
})
})
@@ -1849,44 +1825,44 @@ describe('QSelect API', () => {
describe('(method): getEmittingOptionValue', () => {
it('should return the emit value with plain options', () => {
const options = [ '1', '2', '3', '4' ]
- const model = ref('1')
- mount(WrapperOne, {
- attrs: {
- modelValue: model,
+ const modelValue = '1'
+ mountQSelect({
+ props: {
+ modelValue,
options
}
})
.then(() => {
- expect(Cypress.vueWrapper.vm.compRef.getEmittingOptionValue(options[ 2 ])).to.equal(options[ 2 ])
+ expect(Cypress.vueWrapper.vm.getEmittingOptionValue(options[ 2 ])).to.equal(options[ 2 ])
})
})
it('should return the emit value with object options', () => {
const options = [ { label: '1', value: 1 }, { label: '2', value: 2 }, { label: '3', value: 3 } ]
- const model = ref(options[ 0 ])
- mount(WrapperOne, {
- attrs: {
- modelValue: model,
+ const modelValue = options[ 0 ]
+ mountQSelect({
+ props: {
+ modelValue,
options
}
})
.then(() => {
- expect(Cypress.vueWrapper.vm.compRef.getEmittingOptionValue(options[ 2 ])).to.equal(options[ 2 ])
+ expect(Cypress.vueWrapper.vm.getEmittingOptionValue(options[ 2 ])).to.equal(options[ 2 ])
})
})
it('should respect emit-value when using options', () => {
const options = [ { label: '1', value: 1 }, { label: '2', value: 2 }, { label: '3', value: 3 } ]
- const model = ref(options[ 0 ])
- mount(WrapperOne, {
- attrs: {
- modelValue: model,
+ const modelValue = options[ 0 ]
+ mountQSelect({
+ props: {
+ modelValue,
options,
emitValue: true
}
})
.then(() => {
- expect(Cypress.vueWrapper.vm.compRef.getEmittingOptionValue(options[ 2 ])).to.equal(options[ 2 ].value)
+ expect(Cypress.vueWrapper.vm.getEmittingOptionValue(options[ 2 ])).to.equal(options[ 2 ].value)
})
})
})
@@ -1894,44 +1870,44 @@ describe('QSelect API', () => {
describe('(method): getOptionValue', () => {
it('should return the option value with plain options', () => {
const options = [ '1', '2', '3', '4' ]
- const model = ref('1')
- mount(WrapperOne, {
- attrs: {
- modelValue: model,
+ const modelValue = '1'
+ mountQSelect({
+ props: {
+ modelValue,
options
}
})
.then(() => {
- expect(Cypress.vueWrapper.vm.compRef.getOptionValue(options[ 2 ])).to.equal(options[ 2 ])
+ expect(Cypress.vueWrapper.vm.getOptionValue(options[ 2 ])).to.equal(options[ 2 ])
})
})
it('should return the option value with object options (value by default)', () => {
const options = [ { label: '1', value: 1 }, { label: '2', value: 2 }, { label: '3', value: 3 } ]
- const model = ref(options[ 0 ])
- mount(WrapperOne, {
- attrs: {
- modelValue: model,
+ const modelValue = options[ 0 ]
+ mountQSelect({
+ props: {
+ modelValue,
options
}
})
.then(() => {
- expect(Cypress.vueWrapper.vm.compRef.getOptionValue(options[ 2 ])).to.equal(options[ 2 ].value)
+ expect(Cypress.vueWrapper.vm.getOptionValue(options[ 2 ])).to.equal(options[ 2 ].value)
})
})
it('should respect the option-value option', () => {
const options = [ { label: '1', test: 1 }, { label: '2', test: 2 }, { label: '3', test: 3 } ]
- const model = ref(options[ 0 ])
- mount(WrapperOne, {
- attrs: {
- modelValue: model,
+ const modelValue = options[ 0 ]
+ mountQSelect({
+ props: {
+ modelValue,
options,
optionValue: 'test'
}
})
.then(() => {
- expect(Cypress.vueWrapper.vm.compRef.getOptionValue(options[ 2 ])).to.equal(options[ 2 ].test)
+ expect(Cypress.vueWrapper.vm.getOptionValue(options[ 2 ])).to.equal(options[ 2 ].test)
})
})
})
@@ -1939,44 +1915,44 @@ describe('QSelect API', () => {
describe('(method): getOptionLabel', () => {
it('should return the option label with plain options', () => {
const options = [ '1', '2', '3', '4' ]
- const model = ref('1')
- mount(WrapperOne, {
- attrs: {
- modelValue: model,
+ const modelValue = '1'
+ mountQSelect({
+ props: {
+ modelValue,
options
}
})
.then(() => {
- expect(Cypress.vueWrapper.vm.compRef.getOptionLabel(options[ 2 ])).to.equal(options[ 2 ])
+ expect(Cypress.vueWrapper.vm.getOptionLabel(options[ 2 ])).to.equal(options[ 2 ])
})
})
it('should return the option label with object options (label by default)', () => {
const options = [ { label: '1', value: 1 }, { label: '2', value: 2 }, { label: '3', value: 3 } ]
- const model = ref(options[ 0 ])
- mount(WrapperOne, {
- attrs: {
- modelValue: model,
+ const modelValue = options[ 0 ]
+ mountQSelect({
+ props: {
+ modelValue,
options
}
})
.then(() => {
- expect(Cypress.vueWrapper.vm.compRef.getOptionLabel(options[ 2 ])).to.equal(options[ 2 ].label)
+ expect(Cypress.vueWrapper.vm.getOptionLabel(options[ 2 ])).to.equal(options[ 2 ].label)
})
})
it('should respect the option-value option', () => {
const options = [ { test: '1', value: 1 }, { test: '2', value: 2 }, { test: '3', value: 3 } ]
- const model = ref(options[ 0 ])
- mount(WrapperOne, {
- attrs: {
- modelValue: model,
+ const modelValue = options[ 0 ]
+ mountQSelect({
+ props: {
+ modelValue,
options,
optionLabel: 'test'
}
})
.then(() => {
- expect(Cypress.vueWrapper.vm.compRef.getOptionLabel(options[ 2 ])).to.equal(options[ 2 ].test)
+ expect(Cypress.vueWrapper.vm.getOptionLabel(options[ 2 ])).to.equal(options[ 2 ].test)
})
})
})
@@ -1984,18 +1960,18 @@ describe('QSelect API', () => {
describe('(method): isOptionDisabled', () => {
it('should return if an option is disabled correctly', () => {
const options = [ { label: '1', value: 1, disable: true }, { label: '2', value: 2 }, { label: '3', value: 3 } ]
- const model = ref(options[ 0 ])
- mount(WrapperOne, {
- attrs: {
- modelValue: model,
+ const modelValue = options[ 0 ]
+ mountQSelect({
+ props: {
+ modelValue,
options
}
})
.then(() => {
- expect(Cypress.vueWrapper.vm.compRef.isOptionDisabled(options[ 0 ])).to.be.true
+ expect(Cypress.vueWrapper.vm.isOptionDisabled(options[ 0 ])).to.be.true
// This currently fails: https://github.com/quasarframework/quasar/issues/12046
- // expect(Cypress.vueWrapper.vm.compRef.isOptionDisabled(options[ 1 ])).to.be.false
- // expect(Cypress.vueWrapper.vm.compRef.isOptionDisabled(options[ 2 ])).to.be.false
+ // expect(Cypress.vueWrapper.vm.isOptionDisabled(options[ 1 ])).to.be.false
+ // expect(Cypress.vueWrapper.vm.isOptionDisabled(options[ 2 ])).to.be.false
})
})
})
diff --git a/ui/src/components/select/__tests__/WrapperOne.vue b/ui/src/components/select/__tests__/WrapperOne.vue
deleted file mode 100644
index 4d89eb63a27..00000000000
--- a/ui/src/components/select/__tests__/WrapperOne.vue
+++ /dev/null
@@ -1,28 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
diff --git a/ui/src/composables/private/__tests__/use-anchor.spec.js b/ui/src/composables/private/__tests__/use-anchor.spec.js
index 496c24fac12..a6b9b70ef35 100644
--- a/ui/src/composables/private/__tests__/use-anchor.spec.js
+++ b/ui/src/composables/private/__tests__/use-anchor.spec.js
@@ -7,7 +7,7 @@ describe('use-anchor API', () => {
describe('(prop): target', () => {
it('should use another target using a CSS selector', () => {
mount(WrapperOne, {
- attrs: {
+ props: {
target: '.other-target'
}
})
@@ -27,7 +27,7 @@ describe('use-anchor API', () => {
it('should not show when target is false', () => {
mount(WrapperOne, {
- attrs: {
+ props: {
target: false
}
})
@@ -42,7 +42,7 @@ describe('use-anchor API', () => {
describe('(prop): no-parent-event', () => {
it('should not show when clicking parent with no-parent-event true', () => {
mount(WrapperOne, {
- attrs: {
+ props: {
'no-parent-event': true
}
})
@@ -55,7 +55,7 @@ describe('use-anchor API', () => {
it('should show when clicking parent with no-parent-event false', () => {
mount(WrapperOne, {
- attrs: {
+ props: {
'no-parent-event': false
}
})
@@ -70,7 +70,7 @@ describe('use-anchor API', () => {
describe('(prop): context-menu', () => {
it('should not show when left clicking parent', () => {
mount(WrapperOne, {
- attrs: {
+ props: {
'context-menu': true
}
})
@@ -83,7 +83,7 @@ describe('use-anchor API', () => {
it('should show when right clicking parent', () => {
mount(WrapperOne, {
- attrs: {
+ props: {
'context-menu': true
}
})
diff --git a/ui/src/composables/private/__tests__/use-field.spec.js b/ui/src/composables/private/__tests__/use-field.spec.js
index 4515361279c..cba362d9d9c 100644
--- a/ui/src/composables/private/__tests__/use-field.spec.js
+++ b/ui/src/composables/private/__tests__/use-field.spec.js
@@ -42,7 +42,7 @@ describe('use-field API', () => {
it('should show the label when supplied', () => {
const label = 'Select something'
mount(FieldWrapper, {
- attrs: {
+ props: {
label
}
})
@@ -53,7 +53,7 @@ describe('use-field API', () => {
it('should show the label centered when not focused', () => {
const label = 'Select something'
mount(FieldWrapper, {
- attrs: {
+ props: {
label
}
})
@@ -66,7 +66,7 @@ describe('use-field API', () => {
it('should show the label stacked when focused', () => {
const label = 'Select something'
mount(FieldWrapper, {
- attrs: {
+ props: {
label
}
})
@@ -82,7 +82,7 @@ describe('use-field API', () => {
it('should show the label stacked', () => {
const label = 'Select something'
mount(FieldWrapper, {
- attrs: {
+ props: {
label,
stackLabel: true
}
@@ -97,7 +97,7 @@ describe('use-field API', () => {
it('should show a hint text', () => {
const hint = 'Select something'
mount(FieldWrapper, {
- attrs: {
+ props: {
hint
}
})
@@ -110,7 +110,7 @@ describe('use-field API', () => {
it('should not show a hint text when not focused', () => {
const hint = 'Select something'
mount(FieldWrapper, {
- attrs: {
+ props: {
hint,
hideHint: true
}
@@ -121,7 +121,7 @@ describe('use-field API', () => {
it('should show a hint text when focused', () => {
const hint = 'Select something'
mount(FieldWrapper, {
- attrs: {
+ props: {
hint,
hideHint: true
}
diff --git a/ui/src/composables/private/__tests__/use-model-toggle.spec.js b/ui/src/composables/private/__tests__/use-model-toggle.spec.js
index 356f899921c..1f65fe43ae9 100644
--- a/ui/src/composables/private/__tests__/use-model-toggle.spec.js
+++ b/ui/src/composables/private/__tests__/use-model-toggle.spec.js
@@ -3,40 +3,41 @@ import { mount } from '@cypress/vue'
import WrapperOne from './../../../components/menu/__tests__/WrapperOne.vue'
import WrapperTwo from './../../../components/menu/__tests__/WrapperTwo.vue'
import { ref } from 'vue'
+import { vModelAdapter } from '../../../../test/cypress/helpers/v-model-adapter'
describe('use-model-toggle API', () => {
describe('Props', () => {
describe('Category: model', () => {
describe('(prop): model-value', () => {
it('should open the dialog when modifying the model-value', () => {
- const modelValue = ref(false)
+ const model = ref(false)
mount(WrapperOne, {
- attrs: {
- modelValue
+ props: {
+ ...vModelAdapter(model)
}
})
cy.dataCy('wrapper')
cy.dataCy('menu')
.should('not.exist')
.then(() => {
- modelValue.value = true
+ model.value = true
cy.dataCy('menu')
.should('exist')
})
})
it('should close the dialog when modifying the model-value', () => {
- const modelValue = ref(true)
+ const model = ref(true)
mount(WrapperOne, {
- attrs: {
- modelValue
+ props: {
+ ...vModelAdapter(model)
}
})
cy.dataCy('wrapper')
cy.dataCy('menu')
.should('exist')
.then(() => {
- modelValue.value = false
+ model.value = false
cy.dataCy('menu')
.should('not.exist')
})
@@ -50,7 +51,7 @@ describe('use-model-toggle API', () => {
it('should emit @update:model-value event when state changes', () => {
const fn = cy.stub()
mount(WrapperOne, {
- attrs: {
+ props: {
'onUpdate:modelValue': fn
}
})
@@ -70,7 +71,7 @@ describe('use-model-toggle API', () => {
it('should emit @show event when menu is triggered by parent', () => {
const fn = cy.stub()
mount(WrapperOne, {
- attrs: {
+ props: {
onShow: fn
}
})
@@ -89,7 +90,7 @@ describe('use-model-toggle API', () => {
it('should emit @show event when component is triggered with the show() method', () => {
const fn = cy.stub()
mount(WrapperOne, {
- attrs: {
+ props: {
onShow: fn
}
})
@@ -111,7 +112,7 @@ describe('use-model-toggle API', () => {
it('should emit @before-show event when menu is triggered by parent', () => {
const fn = cy.stub()
mount(WrapperOne, {
- attrs: {
+ props: {
onBeforeShow: fn
}
})
@@ -129,7 +130,7 @@ describe('use-model-toggle API', () => {
it('should emit @before-show event when component is triggered with the show() method', () => {
const fn = cy.stub()
mount(WrapperOne, {
- attrs: {
+ props: {
onBeforeShow: fn
}
})
@@ -150,7 +151,7 @@ describe('use-model-toggle API', () => {
it('should emit @hide event when menu is triggered by parent', () => {
const fn = cy.stub()
mount(WrapperOne, {
- attrs: {
+ props: {
onHide: fn
}
})
@@ -175,7 +176,7 @@ describe('use-model-toggle API', () => {
it('should emit @hide event when component is triggered with the show() method', () => {
const fn = cy.stub()
mount(WrapperOne, {
- attrs: {
+ props: {
onHide: fn
}
})
@@ -203,7 +204,7 @@ describe('use-model-toggle API', () => {
it('should emit @before-hide event when menu is triggered by parent', () => {
const fn = cy.stub()
mount(WrapperOne, {
- attrs: {
+ props: {
onBeforeHide: fn
}
})
@@ -228,7 +229,7 @@ describe('use-model-toggle API', () => {
it('should emit @before-hide event when component is triggered with the show() method', () => {
const fn = cy.stub()
mount(WrapperOne, {
- attrs: {
+ props: {
onBeforeHide: fn
}
})
diff --git a/ui/src/composables/private/__tests__/use-transition.spec.js b/ui/src/composables/private/__tests__/use-transition.spec.js
index 182eebff2e2..ffa6a908b34 100644
--- a/ui/src/composables/private/__tests__/use-transition.spec.js
+++ b/ui/src/composables/private/__tests__/use-transition.spec.js
@@ -16,7 +16,7 @@ describe('use-transition API', () => {
it('should use a different show transition if defined', () => {
const transition = 'scale'
mount(WrapperOne, {
- attrs: {
+ props: {
transitionShow: transition
}
})
@@ -43,7 +43,7 @@ describe('use-transition API', () => {
it('should use a different hide transition if defined', () => {
const transition = 'scale'
mount(WrapperOne, {
- attrs: {
+ props: {
transitionHide: transition
}
})
@@ -64,7 +64,7 @@ describe('use-transition API', () => {
cy.dataCy('wrapper')
.click()
.wait(300)
- cy.dataCy('menu', { timeout: 0 }) // Disable retry
+ cy.dataCy('menu', { timeout: 350 })
.should('not.have.class', 'q-transition--fade-enter-active')
})
@@ -79,7 +79,7 @@ describe('use-transition API', () => {
it('should be done after a custom 1000ms passed', () => {
mount(WrapperOne, {
- attrs: {
+ props: {
transitionDuration: 1000
}
})
@@ -92,7 +92,7 @@ describe('use-transition API', () => {
it('should not be done before a custom 1000ms passed', () => {
mount(WrapperOne, {
- attrs: {
+ props: {
transitionDuration: 1000
}
})
diff --git a/ui/src/composables/private/__tests__/use-validate.spec.js b/ui/src/composables/private/__tests__/use-validate.spec.js
index ab1e9a75138..85c68895952 100644
--- a/ui/src/composables/private/__tests__/use-validate.spec.js
+++ b/ui/src/composables/private/__tests__/use-validate.spec.js
@@ -37,7 +37,7 @@ describe('use-validate API', () => {
it('should show an error-message when error is true', () => {
const message = 'Please select something'
mount(FieldWrapper, {
- attrs: {
+ props: {
error: true,
errorMessage: message
}
@@ -49,7 +49,7 @@ describe('use-validate API', () => {
it('should not show an error-message when error is false', () => {
const message = 'Please select something'
mount(FieldWrapper, {
- attrs: {
+ props: {
error: false,
errorMessage: message
}
@@ -62,7 +62,7 @@ describe('use-validate API', () => {
describe('(prop): no-error-icon', () => {
it('should not show an error icon when error is true', () => {
mount(FieldWrapper, {
- attrs: {
+ props: {
error: true,
noErrorIcon: true
}
@@ -74,7 +74,7 @@ describe('use-validate API', () => {
it('should show an error icon when error is true an no-error-icon is false', () => {
mount(FieldWrapper, {
- attrs: {
+ props: {
error: true,
noErrorIcon: false
}
diff --git a/ui/test/cypress/helpers/v-model-adapter.js b/ui/test/cypress/helpers/v-model-adapter.js
new file mode 100644
index 00000000000..fb5093786da
--- /dev/null
+++ b/ui/test/cypress/helpers/v-model-adapter.js
@@ -0,0 +1,17 @@
+import { watch } from 'vue'
+
+// VTU won't accept reactive v-model binding, this adapter manually
+// set the model prop each time a new value is emitted
+// See https://github.com/vuejs/test-utils/discussions/279
+
+// See https://github.com/vuejs/test-utils/issues/871
+export function vModelAdapter (modelRef, modelName = 'modelValue') {
+ watch(modelRef, (value) => Cypress.vueWrapper.setProps({ [ modelName ]: value }))
+
+ return {
+ [ modelName ]: modelRef.value,
+ [ `onUpdate:${ modelName }` ]: (emittedValue) => {
+ modelRef.value = emittedValue
+ }
+ }
+}
diff --git a/ui/tsconfig.json b/ui/tsconfig.json
index b8a21b10d21..41f26abc717 100644
--- a/ui/tsconfig.json
+++ b/ui/tsconfig.json
@@ -1,5 +1,6 @@
{
"compilerOptions": {
+ "jsx": "preserve",
"allowJs": true,
"target": "esnext",
"module": "esnext",
@@ -8,4 +9,4 @@
"outDir": "./dist"
},
"include": ["./src/**/*", "./test/cypress/**/*.d.ts", "./test/cypress/support/commands.js"]
-}
\ No newline at end of file
+}