From 09090f6417f4e3a9724e831ed6c321ddd3f67535 Mon Sep 17 00:00:00 2001 From: Milos Paunovic Date: Sat, 14 May 2022 21:51:30 +0200 Subject: [PATCH 01/17] feat: Added GitHub action for test running --- .github/workflows/tests-on-pr.yml | 63 +++++++++++++++++++ CONTRIBUTING.md | 2 + ui/dev/cypress.json | 1 + .../select/__tests__/QSelect.spec.js | 13 +++- .../private/__tests__/use-transition.spec.js | 2 +- 5 files changed, 78 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/tests-on-pr.yml diff --git a/.github/workflows/tests-on-pr.yml b/.github/workflows/tests-on-pr.yml new file mode 100644 index 00000000000..9c9ae87e914 --- /dev/null +++ b/.github/workflows/tests-on-pr.yml @@ -0,0 +1,63 @@ +name: UI Tests + +on: + pull_request: + types: [opened, edited, synchronize ] + branches: + - 'dev' + paths: + - 'ui/**' + +jobs: + tests: + runs-on: ubuntu-latest + env: + SUMMARY: | + Hi @${{ github.event.pull_request.user.login }}! 👋 + + It looks like you've opened a pull request [#${{github.event.pull_request.number}}](https://github.com/quasarframework/quasar/pull/${{github.event.pull_request.number}}). Thanks for the contribution! 👏 + + We've detected file changes inside the `ui` folder, so that triggered our Cypress component tests. + + SUCCESS: | + :white_check_mark: Seems like all the tests passed successfully, so your PR is ready to be reviewed! + + FAILURE: | + :bangbang: Seems like some of the tests are failing. Please amend 'em for someone from the team to be able to review it. + + strategy: + fail-fast: false + + name: 'UI tests' + 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 + uses: cypress-io/github-action@v2 + with: + record: true + command: npm run test:component:ci + working-directory: ui + 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 + + - name: Add workflow summary + run: echo "$SUMMARY" >> $GITHUB_STEP_SUMMARY + if: always() + + - + run: echo "$FAILURE" >> $GITHUB_STEP_SUMMARY + if: failure() || cancelled() + + - 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/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/src/components/select/__tests__/QSelect.spec.js b/ui/src/components/select/__tests__/QSelect.spec.js index 4550ae8ba69..b91ccfd4d4b 100644 --- a/ui/src/components/select/__tests__/QSelect.spec.js +++ b/ui/src/components/select/__tests__/QSelect.spec.js @@ -72,11 +72,17 @@ describe('QSelect API', () => { .should('exist') }) - it('should not render an input by default', () => { + it('should render an input, but it shouldn\'t be visible', () => { mount(WrapperOne) + cy.get('.select-root') .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 }) }) @@ -250,6 +256,9 @@ describe('QSelect API', () => { .then(() => { expect(model.value).to.equal(options[ 0 ]) }) + + cy.get('.select-root') + .click() cy.get('.q-menu') .contains('Option 2') .click() diff --git a/ui/src/composables/private/__tests__/use-transition.spec.js b/ui/src/composables/private/__tests__/use-transition.spec.js index 182eebff2e2..c82fe7d27cf 100644 --- a/ui/src/composables/private/__tests__/use-transition.spec.js +++ b/ui/src/composables/private/__tests__/use-transition.spec.js @@ -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: 300 }) .should('not.have.class', 'q-transition--fade-enter-active') }) From caebc6f1adc4fe94b0ef121263e47be29869eb10 Mon Sep 17 00:00:00 2001 From: Milos Paunovic Date: Sat, 14 May 2022 21:58:57 +0200 Subject: [PATCH 02/17] chore: Dealt with unnamed steps in workflow --- .github/workflows/tests-on-pr.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests-on-pr.yml b/.github/workflows/tests-on-pr.yml index 9c9ae87e914..1edbe9c2031 100644 --- a/.github/workflows/tests-on-pr.yml +++ b/.github/workflows/tests-on-pr.yml @@ -55,9 +55,10 @@ jobs: run: echo "$SUMMARY" >> $GITHUB_STEP_SUMMARY if: always() - - + - name: Output failure message run: echo "$FAILURE" >> $GITHUB_STEP_SUMMARY if: failure() || cancelled() - - run: echo "$SUCCESS" >> $GITHUB_STEP_SUMMARY + - name: Output success message + run: echo "$SUCCESS" >> $GITHUB_STEP_SUMMARY if: success() \ No newline at end of file From a7b45ae7e7d0f95317bcc2a6aefd50aa20b84d9b Mon Sep 17 00:00:00 2001 From: Milos Paunovic Date: Sat, 14 May 2022 22:01:07 +0200 Subject: [PATCH 03/17] chore: Added workflow badge to READE.md file --- README.md | 2 ++ 1 file changed, 2 insertions(+) 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 From 3af53c199ada49614e7ec5bf6c5f0c6a756fe6e6 Mon Sep 17 00:00:00 2001 From: Paolo Caleffi Date: Wed, 18 May 2022 18:07:50 +0200 Subject: [PATCH 04/17] tests(QSelect): fix "multiple" prop tests --- .../select/__tests__/QSelect.spec.js | 97 ++++++++++--------- ui/test/cypress/helpers/v-model-adapter.js | 13 +++ ui/tsconfig.json | 3 +- 3 files changed, 67 insertions(+), 46 deletions(-) create mode 100644 ui/test/cypress/helpers/v-model-adapter.js diff --git a/ui/src/components/select/__tests__/QSelect.spec.js b/ui/src/components/select/__tests__/QSelect.spec.js index b91ccfd4d4b..7e12ee45dc0 100644 --- a/ui/src/components/select/__tests__/QSelect.spec.js +++ b/ui/src/components/select/__tests__/QSelect.spec.js @@ -1,8 +1,14 @@ /* eslint-disable no-unused-expressions */ import { mount } from '@cypress/vue' -import { ref, h } from 'vue' +import { h, ref } from 'vue' +import { vModelAdapter } from '../../../../test/cypress/helpers/v-model-adapter.js' +import QSelect from '../QSelect.js' import WrapperOne from './WrapperOne.vue' +function getHostElement () { + return cy.get('.q-select') +} + // 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 describe('QSelect API', () => { @@ -234,66 +240,67 @@ describe('QSelect API', () => { }) }) - describe('Category: model|selection', () => { - describe('(prop): multiple', () => { + // eslint-disable-next-line no-only-tests/no-only-tests + describe.only('Category: model|selection', () => { + // eslint-disable-next-line no-only-tests/no-only-tests + describe.only('(prop): multiple', () => { 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 - }, + mount(QSelect, { + 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('.select-root') - .click() - 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: { + mount(QSelect, { + 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) + }) + } + }) }) }) }) 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..4057e580f20 --- /dev/null +++ b/ui/test/cypress/helpers/v-model-adapter.js @@ -0,0 +1,13 @@ +// 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') { + return { + [ modelName ]: modelRef.value, + [ `onUpdate:${ modelName }` ]: (val) => { + modelRef.value = val + Cypress.vueWrapper.setProps({ modelValue: val }) + } + } +} 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 +} From 98dbbeae5a8192266ccc1e2857750a8cbdf9bdf0 Mon Sep 17 00:00:00 2001 From: Paolo Caleffi Date: Wed, 18 May 2022 18:18:22 +0200 Subject: [PATCH 05/17] test(QSelect): remove .only modifiers --- ui/src/components/select/__tests__/QSelect.spec.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/ui/src/components/select/__tests__/QSelect.spec.js b/ui/src/components/select/__tests__/QSelect.spec.js index 7e12ee45dc0..5333ed84bf2 100644 --- a/ui/src/components/select/__tests__/QSelect.spec.js +++ b/ui/src/components/select/__tests__/QSelect.spec.js @@ -240,10 +240,8 @@ describe('QSelect API', () => { }) }) - // eslint-disable-next-line no-only-tests/no-only-tests - describe.only('Category: model|selection', () => { - // eslint-disable-next-line no-only-tests/no-only-tests - describe.only('(prop): multiple', () => { + describe('Category: model|selection', () => { + describe('(prop): multiple', () => { it('should select only one option by default', () => { const options = [ 'Option 1', 'Option 2' ] const model = ref(null) From 301d568dc8f186cf073a36bbfd8359e7c1e0a196 Mon Sep 17 00:00:00 2001 From: Paolo Caleffi Date: Wed, 18 May 2022 18:44:41 +0200 Subject: [PATCH 06/17] test(QSelect): refactor and fix all tests --- ui/src/components/select/QSelect.js | 2 +- .../select/__tests__/QSelect.spec.js | 786 +++++++++--------- .../select/__tests__/WrapperOne.vue | 28 - 3 files changed, 375 insertions(+), 441 deletions(-) delete mode 100644 ui/src/components/select/__tests__/WrapperOne.vue 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 5333ed84bf2..43342b22841 100644 --- a/ui/src/components/select/__tests__/QSelect.spec.js +++ b/ui/src/components/select/__tests__/QSelect.spec.js @@ -3,10 +3,20 @@ import { mount } from '@cypress/vue' import { h, ref } from 'vue' import { vModelAdapter } from '../../../../test/cypress/helpers/v-model-adapter.js' import QSelect from '../QSelect.js' -import WrapperOne from './WrapperOne.vue' -function getHostElement () { - return cy.get('.q-select') +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 @@ -55,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') }) @@ -68,20 +78,20 @@ 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 render an input, but it shouldn\'t be visible', () => { - mount(WrapperOne) + mountQSelect() - cy.get('.select-root') + getHostElement() .get('input') .should('not.be.visible') }) @@ -96,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(() => { @@ -117,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) @@ -142,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') }) @@ -164,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') }) }) @@ -188,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) }) }) @@ -202,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') @@ -222,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') @@ -245,7 +255,7 @@ describe('QSelect API', () => { it('should select only one option by default', () => { const options = [ 'Option 1', 'Option 2' ] const model = ref(null) - mount(QSelect, { + mountQSelect({ props: { ...vModelAdapter(model), options @@ -274,7 +284,7 @@ describe('QSelect API', () => { it('should select multiple options if multiple is true', () => { const options = [ 'Option 1', 'Option 2' ] const model = ref([]) - mount(QSelect, { + mountQSelect({ props: { ...vModelAdapter(model), multiple: true, @@ -307,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() @@ -327,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) @@ -350,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) @@ -374,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) @@ -399,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() @@ -414,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() @@ -430,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() @@ -447,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"]') @@ -461,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"]') @@ -477,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"]') @@ -495,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') @@ -512,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') @@ -529,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 ]) @@ -545,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 ]) @@ -562,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 ]) @@ -586,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') @@ -601,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') @@ -619,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 }) }) @@ -648,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 }) @@ -670,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) }) }) @@ -713,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' @@ -752,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') @@ -762,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') @@ -778,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 @@ -788,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 @@ -805,7 +806,7 @@ describe('QSelect API', () => { 'selected-item': () => html } }) - cy.get('.select-root') + getHostElement() .contains(html) }) }) @@ -813,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, @@ -836,7 +837,7 @@ describe('QSelect API', () => { useInput: true } }) - cy.get('.select-root') + getHostElement() .get('input') .should('have.value', options[ 0 ]) }) @@ -846,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) }) }) }) @@ -872,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 ]) }) @@ -890,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) @@ -906,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') @@ -922,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) }) @@ -937,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') }) @@ -956,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 ] }, @@ -965,7 +963,7 @@ describe('QSelect API', () => { selected: () => selectedString } }) - cy.get('.select-root') + getHostElement() .should('contain', selectedString) }) }) @@ -973,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() @@ -1020,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() @@ -1039,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) @@ -1055,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 }, @@ -1064,7 +1062,7 @@ describe('QSelect API', () => { 'no-option': (scope) => compareString + scope.inputValue } }) - cy.get('.select-root') + getHostElement() .click() .type('Hello') cy.get('.q-menu') @@ -1073,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) @@ -1091,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 }, @@ -1100,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 }, @@ -1116,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 }, @@ -1131,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') }) @@ -1161,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') }) @@ -1186,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') @@ -1203,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 }, @@ -1212,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') @@ -1226,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 @@ -1235,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"]') @@ -1250,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 @@ -1259,7 +1251,7 @@ describe('QSelect API', () => { }) expect(fn).not.to.be.called - cy.get('.select-root') + getHostElement() .get('input') .type('h') .then(() => { @@ -1272,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"]') @@ -1309,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"]') @@ -1339,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(() => { @@ -1367,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}') @@ -1395,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 @@ -1404,7 +1384,7 @@ describe('QSelect API', () => { }) expect(fn).not.to.be.called - cy.get('.select-root') + getHostElement() .get('input') .type('h') .then(() => { @@ -1417,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, @@ -1427,7 +1407,7 @@ describe('QSelect API', () => { }) expect(fn).not.to.be.called - cy.get('.select-root') + getHostElement() .get('input') .click() .then(() => { @@ -1442,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() }, @@ -1454,7 +1434,7 @@ describe('QSelect API', () => { }) expect(fn).not.to.be.called - cy.get('.select-root') + getHostElement() .get('input') .click() .then(() => { @@ -1470,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 @@ -1489,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 @@ -1522,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') }) @@ -1539,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' ] } }) @@ -1548,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') }) @@ -1560,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') @@ -1582,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 }) }) @@ -1603,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) }) }) @@ -1643,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) }) }) @@ -1669,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') @@ -1697,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') @@ -1727,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() @@ -1746,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() @@ -1773,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) }) }) @@ -1801,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') @@ -1823,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') @@ -1845,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 }) }) }) @@ -1863,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) }) }) }) @@ -1908,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) }) }) }) @@ -1953,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) }) }) }) @@ -1998,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 @@ - - - From fee5bb269ed6dd191329b2195ed8077e528691aa Mon Sep 17 00:00:00 2001 From: Paolo Caleffi Date: Thu, 19 May 2022 10:49:57 +0200 Subject: [PATCH 07/17] test(model-toggle): fix tests using reactive variables --- .../private/__tests__/use-model-toggle.spec.js | 13 +++++++------ ui/test/cypress/helpers/v-model-adapter.js | 10 +++++++--- 2 files changed, 14 insertions(+), 9 deletions(-) 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..ea552a55bab 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 + ...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 + ...vModelAdapter(model) } }) cy.dataCy('wrapper') cy.dataCy('menu') .should('exist') .then(() => { - modelValue.value = false + model.value = false cy.dataCy('menu') .should('not.exist') }) diff --git a/ui/test/cypress/helpers/v-model-adapter.js b/ui/test/cypress/helpers/v-model-adapter.js index 4057e580f20..fb5093786da 100644 --- a/ui/test/cypress/helpers/v-model-adapter.js +++ b/ui/test/cypress/helpers/v-model-adapter.js @@ -1,13 +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 }` ]: (val) => { - modelRef.value = val - Cypress.vueWrapper.setProps({ modelValue: val }) + [ `onUpdate:${ modelName }` ]: (emittedValue) => { + modelRef.value = emittedValue } } } From a407102192e068d4b637ba61316ad6f011069e39 Mon Sep 17 00:00:00 2001 From: Paolo Caleffi Date: Thu, 19 May 2022 10:50:21 +0200 Subject: [PATCH 08/17] refactor(tests): use 'props' instead of 'attrs' --- .../components/menu/__tests__/QMenu.spec.js | 46 +++++++++---------- .../private/__tests__/use-anchor.spec.js | 12 ++--- .../private/__tests__/use-field.spec.js | 14 +++--- .../__tests__/use-model-toggle.spec.js | 22 ++++----- .../private/__tests__/use-transition.spec.js | 8 ++-- .../private/__tests__/use-validate.spec.js | 8 ++-- 6 files changed, 55 insertions(+), 55 deletions(-) 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/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 ea552a55bab..1f65fe43ae9 100644 --- a/ui/src/composables/private/__tests__/use-model-toggle.spec.js +++ b/ui/src/composables/private/__tests__/use-model-toggle.spec.js @@ -12,7 +12,7 @@ describe('use-model-toggle API', () => { it('should open the dialog when modifying the model-value', () => { const model = ref(false) mount(WrapperOne, { - attrs: { + props: { ...vModelAdapter(model) } }) @@ -29,7 +29,7 @@ describe('use-model-toggle API', () => { it('should close the dialog when modifying the model-value', () => { const model = ref(true) mount(WrapperOne, { - attrs: { + props: { ...vModelAdapter(model) } }) @@ -51,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 } }) @@ -71,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 } }) @@ -90,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 } }) @@ -112,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 } }) @@ -130,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 } }) @@ -151,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 } }) @@ -176,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 } }) @@ -204,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 } }) @@ -229,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 c82fe7d27cf..e7d46a2ca25 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 } }) @@ -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 } From 025324b845eb15209dfca83767ff2c3e663a4955 Mon Sep 17 00:00:00 2001 From: Milos Paunovic Date: Fri, 20 May 2022 09:05:06 +0200 Subject: [PATCH 09/17] chore: Allowing extra 50ms margin for transition duration test --- ui/src/composables/private/__tests__/use-transition.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/src/composables/private/__tests__/use-transition.spec.js b/ui/src/composables/private/__tests__/use-transition.spec.js index e7d46a2ca25..ffa6a908b34 100644 --- a/ui/src/composables/private/__tests__/use-transition.spec.js +++ b/ui/src/composables/private/__tests__/use-transition.spec.js @@ -64,7 +64,7 @@ describe('use-transition API', () => { cy.dataCy('wrapper') .click() .wait(300) - cy.dataCy('menu', { timeout: 300 }) + cy.dataCy('menu', { timeout: 350 }) .should('not.have.class', 'q-transition--fade-enter-active') }) From bf8a3401742ba08b5d751f052fcade9e2b854306 Mon Sep 17 00:00:00 2001 From: Milos Paunovic Date: Fri, 20 May 2022 09:16:14 +0200 Subject: [PATCH 10/17] chore: Added both chrome and firefox in browser matrix --- .github/workflows/tests-on-pr.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests-on-pr.yml b/.github/workflows/tests-on-pr.yml index 1edbe9c2031..4f2c2e5f429 100644 --- a/.github/workflows/tests-on-pr.yml +++ b/.github/workflows/tests-on-pr.yml @@ -10,6 +10,9 @@ on: jobs: tests: + strategy: + matrix: + browser: [chrome, firefox] runs-on: ubuntu-latest env: SUMMARY: | @@ -41,12 +44,13 @@ jobs: - name: Install dependencies run: cd ./ui && npm i - - name: Run tests + - name: Run tests in ${{ matrix.browser }} uses: cypress-io/github-action@v2 with: - record: true + browser: ${{ matrix.browser }} command: npm run test:component:ci working-directory: ui + record: true 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 From afb4597000064133c9d4c70683a6909d746b4bf4 Mon Sep 17 00:00:00 2001 From: Milos Paunovic Date: Fri, 20 May 2022 09:20:01 +0200 Subject: [PATCH 11/17] chore: Added Cypress dashboard project ID directly to GH action --- .github/workflows/tests-on-pr.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/tests-on-pr.yml b/.github/workflows/tests-on-pr.yml index 4f2c2e5f429..7127e7cb947 100644 --- a/.github/workflows/tests-on-pr.yml +++ b/.github/workflows/tests-on-pr.yml @@ -52,7 +52,8 @@ jobs: working-directory: ui record: true env: - CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} # Dashboard record key as an environment variable + CYPRESS_PROJECT_ID: "5zr217" # Cypress dashboard project ID + 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 - name: Add workflow summary From 81c84d170a3562b099d3cf3ca4876298fc39ec7b Mon Sep 17 00:00:00 2001 From: Milos Paunovic Date: Fri, 20 May 2022 09:21:25 +0200 Subject: [PATCH 12/17] chore: Amended duplicated strategy key in workflow file --- .github/workflows/tests-on-pr.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/tests-on-pr.yml b/.github/workflows/tests-on-pr.yml index 7127e7cb947..ceaaf814652 100644 --- a/.github/workflows/tests-on-pr.yml +++ b/.github/workflows/tests-on-pr.yml @@ -9,10 +9,7 @@ on: - 'ui/**' jobs: - tests: - strategy: - matrix: - browser: [chrome, firefox] + tests: runs-on: ubuntu-latest env: SUMMARY: | @@ -30,6 +27,8 @@ jobs: strategy: fail-fast: false + matrix: + browser: [chrome, firefox] name: 'UI tests' steps: From cbb6625a973356e4d9d6756a7b39de1b53e84f16 Mon Sep 17 00:00:00 2001 From: Milos Paunovic Date: Fri, 20 May 2022 09:31:27 +0200 Subject: [PATCH 13/17] chore: Improved steps naming in workflow --- .github/workflows/tests-on-pr.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests-on-pr.yml b/.github/workflows/tests-on-pr.yml index ceaaf814652..cfa2eb72a8e 100644 --- a/.github/workflows/tests-on-pr.yml +++ b/.github/workflows/tests-on-pr.yml @@ -30,7 +30,7 @@ jobs: matrix: browser: [chrome, firefox] - name: 'UI tests' + name: ${{ matrix.browser }} steps: - name: Checkout code uses: actions/checkout@v3 @@ -43,7 +43,7 @@ jobs: - name: Install dependencies run: cd ./ui && npm i - - name: Run tests in ${{ matrix.browser }} + - name: Run tests in ${{ matrix.browser }} browser uses: cypress-io/github-action@v2 with: browser: ${{ matrix.browser }} From 7db2c5462c473cbd68108f7bbff049cd3f284493 Mon Sep 17 00:00:00 2001 From: Milos Paunovic Date: Fri, 20 May 2022 14:06:48 +0200 Subject: [PATCH 14/17] chore: Amended workflow summary wording --- .github/workflows/tests-on-pr.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/tests-on-pr.yml b/.github/workflows/tests-on-pr.yml index cfa2eb72a8e..7c52bccb169 100644 --- a/.github/workflows/tests-on-pr.yml +++ b/.github/workflows/tests-on-pr.yml @@ -13,9 +13,7 @@ jobs: runs-on: ubuntu-latest env: SUMMARY: | - Hi @${{ github.event.pull_request.user.login }}! 👋 - - It looks like you've opened a pull request [#${{github.event.pull_request.number}}](https://github.com/quasarframework/quasar/pull/${{github.event.pull_request.number}}). Thanks for the contribution! 👏 + 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. @@ -30,7 +28,7 @@ jobs: matrix: browser: [chrome, firefox] - name: ${{ matrix.browser }} + name: Tests on ${{ matrix.browser }} steps: - name: Checkout code uses: actions/checkout@v3 From 835d62742b2c4688cc3c55a67ef744682dba7ac7 Mon Sep 17 00:00:00 2001 From: Milos Paunovic Date: Sat, 21 May 2022 14:56:57 +0200 Subject: [PATCH 15/17] test: Connected CY dashboard to runs --- .github/workflows/tests-on-pr.yml | 23 +++++++++++------------ ui/package.json | 2 +- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/.github/workflows/tests-on-pr.yml b/.github/workflows/tests-on-pr.yml index 7c52bccb169..905a1a1241f 100644 --- a/.github/workflows/tests-on-pr.yml +++ b/.github/workflows/tests-on-pr.yml @@ -11,17 +11,6 @@ on: jobs: tests: runs-on: ubuntu-latest - 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. - - SUCCESS: | - :white_check_mark: Seems like all the tests passed successfully, so your PR is ready to be reviewed! - - FAILURE: | - :bangbang: Seems like some of the tests are failing. Please amend 'em for someone from the team to be able to review it. strategy: fail-fast: false @@ -47,20 +36,30 @@ jobs: browser: ${{ matrix.browser }} command: npm run test:component:ci working-directory: ui + tag: ${{ github.event_name }} # Tag will be either "push" or "pull_request" record: true env: - CYPRESS_PROJECT_ID: "5zr217" # Cypress dashboard project ID 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/ui/package.json b/ui/package.json index 8969c771359..1b16cf61585 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 && cd ..", "test:create": "node ./test/cypress/helpers/create-spec.js -c" }, "repository": { From de202ac54f560311af0f3c6d6658ecc827e0b791 Mon Sep 17 00:00:00 2001 From: Milos Paunovic Date: Sun, 22 May 2022 16:09:04 +0200 Subject: [PATCH 16/17] test: Trying out test parallelization --- .github/workflows/tests-on-pr.yml | 4 +++- ui/package.json | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests-on-pr.yml b/.github/workflows/tests-on-pr.yml index 905a1a1241f..c9156bc5f99 100644 --- a/.github/workflows/tests-on-pr.yml +++ b/.github/workflows/tests-on-pr.yml @@ -37,7 +37,9 @@ jobs: command: npm run test:component:ci working-directory: ui tag: ${{ github.event_name }} # Tag will be either "push" or "pull_request" - record: true + record: "true" + parallel: "true" + 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 diff --git a/ui/package.json b/ui/package.json index 1b16cf61585..8969c771359 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 --record && cd ..", + "test:component:ci": "cd ./dev && cypress run-ct && cd ..", "test:create": "node ./test/cypress/helpers/create-spec.js -c" }, "repository": { From ad278d633d4aef4688b2cd3a9d507eef01ca46f8 Mon Sep 17 00:00:00 2001 From: Milos Paunovic Date: Sun, 22 May 2022 16:13:20 +0200 Subject: [PATCH 17/17] test: Passing record and parallel props to Cypress from npm script --- .github/workflows/tests-on-pr.yml | 2 -- ui/package.json | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/tests-on-pr.yml b/.github/workflows/tests-on-pr.yml index c9156bc5f99..e34b48647e7 100644 --- a/.github/workflows/tests-on-pr.yml +++ b/.github/workflows/tests-on-pr.yml @@ -37,8 +37,6 @@ jobs: command: npm run test:component:ci working-directory: ui tag: ${{ github.event_name }} # Tag will be either "push" or "pull_request" - record: "true" - parallel: "true" group: Tests in ${{ matrix.browser }} browser env: CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} # Dashboard record key as an environment variable 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": {