Cleaned up frontend testing & Readme file

This commit is contained in:
Elvanos 2023-08-29 00:05:58 +02:00
parent 5e7526882c
commit 8a0ef51133
36 changed files with 75 additions and 976 deletions

View file

@ -11,42 +11,44 @@ Make sure you are running this with Node v16.17.0 ("nvm" is great for these olde
##### Ensure that the Yarn global install location is in your PATH after install. (details in article linked above)
```bash
```
yarn global add @quasar/cli
```
## Install the dependencies and set up the project
```bash
```
yarn
```
### Start the app in Quasar development mode (hot-code reloading, error reporting, etc.)
```bash
```
quasar dev -m electron
```
### Build the app for production
```bash
```
quasar build
```
### Testing:
> Keep in mind that Cypress tests are limited to front-end testing due to the nature of Electron's nodeJS-based backend. Anything in Electron's main and preload will NOT work.
#### Unit test - with pretty web-UI
```bash
```
test:unit:ui
```
#### Unit test - without any UI, fully in a terminal
```bash
test:unit
```
#### Component test - via Cypress, pick Electron on the config screen (I suggest turning on the electron dev window first, the test is a bit buggy sometimes)
```bash
test:component
test:unit:ci
```
#### e2e test - via Cypress, pick Electron on the config screen (I suggest turning on the electron dev window first, the test is a bit buggy sometimes)
```bash
test:e2e
#### Component test, Frontend - via Cypress, pick Electron on the config screen (I suggest turning on the electron dev window first, the test is a bit buggy sometimes)
```
test:component:frontend
```
#### E2E test, Froentend - via Cypress, pick Electron on the config screen (I suggest turning on the electron dev window first, the test is a bit buggy sometimes)
```
test:e2e:frontend
```
### Customize the configuration

View file

@ -22,7 +22,7 @@ export default defineConfig({
return config
},
supportFile: 'test/cypress/support/component.ts',
specPattern: 'src/**/*.cy.{js,jsx,ts,tsx}',
specPattern: 'src/**/*.cy.test.{js,jsx,ts,tsx}',
indexHtmlFile: 'test/cypress/support/component-index.html',
devServer: injectQuasarDevServerConfig()
}

View file

@ -12,10 +12,10 @@
"test:unit:ui": "vitest --ui",
"test:unit": "vitest",
"test:unit:ci": "vitest run",
"test:e2e": "cross-env NODE_ENV=test start-test \"quasar dev\" http-get://localhost:9000 \"cypress open --e2e\"",
"test:e2e:ci": "cross-env NODE_ENV=test start-test \"quasar dev\" http-get://localhost:9000 \"cypress run --e2e\"",
"test:component": "cross-env NODE_ENV=test cypress open --component",
"test:component:ci": "cross-env NODE_ENV=test cypress run --component"
"test:e2e:frontend": "cross-env NODE_ENV=test start-test \"quasar dev\" http-get://localhost:9000 \"cypress open --e2e\"",
"test:e2e:frontend:ci": "cross-env NODE_ENV=test start-test \"quasar dev\" http-get://localhost:9000 \"cypress run --e2e\"",
"test:component:frontend": "cross-env NODE_ENV=test cypress open --component",
"test:component:frontend:ci": "cross-env NODE_ENV=test cypress run --component"
},
"dependencies": {
"@electron/remote": "^2.0.10",

View file

@ -0,0 +1,11 @@
import GlobalWindowButtons from './GlobalWindowButtons.vue'
describe('Component test - GlobalWindowButtons', () => {
it('should have a `accent` color & `dark` background-color', () => {
cy.mount(GlobalWindowButtons)
cy.get('.q-btn-group')
.should('have.backgroundColor', 'var(--q-dark)')
.should('have.color', 'var(--q-accent)')
})
})

View file

@ -0,0 +1,28 @@
import { installQuasar } from '@quasar/quasar-app-extension-testing-unit-vitest'
import { mount } from '@vue/test-utils'
import { describe, expect, it } from 'vitest'
import GlobalWindowButtons from './GlobalWindowButtons.vue'
installQuasar()
describe('Unit test - GlobalWindowButtons component', () => {
it('should mount three buttons', () => {
const wrapper = mount(GlobalWindowButtons)
expect(wrapper.findAll('.q-btn')).toHaveLength(3)
})
it('should have `minimize` button', () => {
const wrapper = mount(GlobalWindowButtons)
expect(wrapper.findAll('.globalWindowButtons__minimize')).toHaveLength(1)
})
it('should have `resize` button', () => {
const wrapper = mount(GlobalWindowButtons)
expect(wrapper.findAll('.globalWindowButtons__minimize')).toHaveLength(1)
})
it('should have `close` button', () => {
const wrapper = mount(GlobalWindowButtons)
expect(wrapper.findAll('.globalWindowButtons__minimize')).toHaveLength(1)
})
})

View file

@ -10,6 +10,7 @@
:ripple="false"
dark
size="xs"
class="globalWindowButtons__minimize"
@click="minimizeWindow()"
>
<q-tooltip
@ -27,6 +28,7 @@
:ripple="false"
dark
size="xs"
class="globalWindowButtons__resize"
@click="[resizeWindow(),checkIfWindowMaximized()]"
>
<q-tooltip
@ -44,6 +46,7 @@
:ripple="false"
dark
size="xs"
class="globalWindowButtons__close"
@click="tryCloseWindow()"
>
<q-tooltip
@ -61,20 +64,23 @@
import { onMounted, ref } from 'vue'
import type { Ref } from 'vue'
// TODO Add all tests!
/*
Triggers minimize of the window by the minimize button click
*/
const minimizeWindow = () => {
window.faWindowControlAPI.minimizeWindow()
console.log(process.env.MODE)
if (process.env.MODE === 'electron') {
window.faWindowControlAPI.minimizeWindow()
}
}
/*
Triggers resize of the window by the min/max button click
*/
const resizeWindow = () => {
window.faWindowControlAPI.resizeWindow()
if (process.env.MODE === 'electron') {
window.faWindowControlAPI.resizeWindow()
}
}
/*
@ -87,14 +93,18 @@ Otherwise, the app simply closes
*/
const tryCloseWindow = () => {
// TODO add project close checking
window.faWindowControlAPI.closeWindow()
if (process.env.MODE === 'electron') {
window.faWindowControlAPI.closeWindow()
}
}
/*
Checks if the window is maximized and sets local ref
*/
const checkIfWindowMaximized = () => {
isMaximized.value = window.faWindowControlAPI.checkWindowMaximized()
if (process.env.MODE === 'electron') {
isMaximized.value = window.faWindowControlAPI.checkWindowMaximized()
}
}
/*

View file

@ -1,19 +0,0 @@
<template>
<q-btn
data-cy="button"
label="test emit"
color="positive"
rounded
icon="edit"
@click="$emit('test')"
/>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
name: 'QuasarButton',
emits: { test: () => true }
})
</script>

View file

@ -1,44 +0,0 @@
<template>
<q-checkbox
v-model="checked"
data-cy="checkbox"
/>
<q-toggle
v-model="toggled"
data-cy="toggle"
/>
<q-radio
v-model="selected"
val="Value1"
data-cy="radio-1"
>
Value1
</q-radio>
<q-radio
v-model="selected"
val="Value2"
data-cy="radio-2"
>
Value2
</q-radio>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue'
export default defineComponent({
name: 'QuasarCheckboxAndToggle',
setup () {
const checked = ref()
const toggled = ref()
const selected = ref()
return {
checked,
toggled,
selected
}
}
})
</script>

View file

@ -1,16 +0,0 @@
<template>
<q-card
data-cy="dark-card"
:dark="$q.dark.isActive"
>
{{ $q.dark.isActive ? 'Dark ' : 'Light' }} content
</q-card>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
name: 'QuasarDark'
})
</script>

View file

@ -1,50 +0,0 @@
<template>
<q-date
v-model="date"
data-cy="date-picker"
/>
<div>
<q-input
v-model="date"
label="Scegli data"
>
<template #append>
<q-btn
data-cy="open-date-picker-popup-button"
icon="event"
flat
round
@click="dateDialogRef.show()"
/>
</template>
</q-input>
<q-dialog ref="dateDialogRef">
<q-date
v-model="date"
@update:model-value="dateDialogRef.hide()"
/>
</q-dialog>
</div>
<span data-cy="date-value">{{ date }}</span>
</template>
<script lang="ts">
import type { QDialog } from 'quasar'
import type { Ref } from 'vue'
import { defineComponent, ref } from 'vue'
export default defineComponent({
name: 'QuasarDate',
setup () {
const date = ref('')
const dateDialogRef = ref() as Ref<QDialog>
return {
date,
dateDialogRef
}
}
})
</script>

View file

@ -1,78 +0,0 @@
<template>
<!-- notice dialogRef here -->
<q-dialog
ref="dialogRef"
@hide="onDialogHide"
>
<q-card>
<q-card-section>{{ message }}</q-card-section>
<!-- buttons example -->
<q-card-actions align="right">
<q-btn
data-cy="ok-button"
color="primary"
label="OK"
@click="onOKClick"
/>
<q-btn
color="primary"
label="Cancel"
@click="onCancelClick"
/>
</q-card-actions>
</q-card>
</q-dialog>
</template>
<script lang="ts">
import { useDialogPluginComponent } from 'quasar'
import { defineComponent } from 'vue'
export default defineComponent({
name: 'QuasarDialog',
props: {
message: {
type: String,
required: true
}
},
// REQUIRED; need to specify some events that your
// component will emit through useDialogPluginComponent()
emits: useDialogPluginComponent.emits,
setup () {
// REQUIRED; must be called inside of setup()
const { dialogRef, onDialogHide, onDialogOK, onDialogCancel } =
useDialogPluginComponent()
// dialogRef - Vue ref to be applied to QDialog
// onDialogHide - Function to be used as handler for @hide on QDialog
// onDialogOK - Function to call to settle dialog with "ok" outcome
// example: onDialogOK() - no payload
// example: onDialogOK({ /*.../* }) - with payload
// onDialogCancel - Function to call to settle dialog with "cancel" outcome
return {
// This is REQUIRED;
// Need to inject these (from useDialogPluginComponent() call)
// into the vue scope for the vue html template
dialogRef,
onDialogHide,
// other methods that we used in our vue html template;
// these are part of our example (so not required)
onOKClick () {
// on OK, it is REQUIRED to
// call onDialogOK (with optional payload)
onDialogOK()
// or with payload: onDialogOK({ ... })
// ...and it will also hide the dialog automatically
},
// we can passthrough onDialogCancel directly
onCancelClick: onDialogCancel
}
}
})
</script>

View file

@ -1,40 +0,0 @@
<template>
<q-drawer
v-model="showDrawer"
show-if-above
:width="200"
:breakpoint="700"
elevated
data-cy="drawer"
class="bg-primary text-white"
>
<q-scroll-area class="fit">
<div class="q-pa-sm">
<div
v-for="n in 50"
:key="n"
>
Drawer {{ n }} / 50
</div>
</div>
<q-btn data-cy="button">
Am I on screen?
</q-btn>
</q-scroll-area>
</q-drawer>
</template>
<script lang="ts">
import { ref, defineComponent } from 'vue'
export default defineComponent({
name: 'QuasarDrawer',
setup () {
const showDrawer = ref(true)
return {
showDrawer
}
}
})
</script>

View file

@ -1,31 +0,0 @@
<template>
<q-btn
data-cy="open-menu-btn"
label="Open menu"
>
<q-menu>
<q-list>
<q-item
v-close-popup
clickable
>
<q-item-section>Item 1</q-item-section>
</q-item>
<q-item
v-close-popup
clickable
>
<q-item-section>Item 2</q-item-section>
</q-item>
</q-list>
</q-menu>
</q-btn>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
name: 'QuasarMenu'
})
</script>

View file

@ -1,29 +0,0 @@
<template>
<q-page-sticky
position="bottom-right"
:offset="[18, 18]"
>
<q-btn
data-cy="button"
rounded
color="accent"
icon="arrow_forward"
>
{{ title }}
</q-btn>
</q-page-sticky>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
name: 'QuasarPageSticky',
props: {
title: {
type: String,
required: true
}
}
})
</script>

View file

@ -1,54 +0,0 @@
<template>
<q-select
v-model="selected"
data-cy="select"
label="test options selection"
:options="options"
:loading="loading"
:disable="disable"
/>
<span data-cy="select-value">{{ selected }}</span>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue'
const syncOptions = ['Option 1', 'Option 2', 'Option 3']
export default defineComponent({
name: 'QuasarSelect',
props: {
loadOptionsAsync: {
type: Boolean,
default: false
},
disable: {
type: Boolean,
default: false
}
},
setup (props) {
const selected = ref()
const loading = ref(false)
const options = ref()
if (props.loadOptionsAsync) {
loading.value = true
setTimeout(() => {
options.value = syncOptions
loading.value = false
}, 2000)
} else {
options.value = syncOptions
}
return {
loading,
selected,
options
}
}
})
</script>

View file

@ -1,31 +0,0 @@
<template>
<q-btn
color="primary"
data-cy="button"
>
Button
<q-tooltip
v-model="showTooltip"
data-cy="tooltip"
class="bg-red"
:offset="[10, 10]"
>
Here I am!
</q-tooltip>
</q-btn>
</template>
<script lang="ts">
import { ref, defineComponent } from 'vue'
export default defineComponent({
name: 'QuasarTooltip',
setup () {
const showTooltip = ref(true)
return {
showTooltip
}
}
})
</script>

View file

@ -1,32 +0,0 @@
<template>
<div>
<span data-cy="model-value">{{ modelValue }}</span>
<button
data-cy="button"
@click="
$emit(
'update:modelValue',
modelValue.length > 0 ? modelValue.substring(1) : ''
)
"
>
Remove first letter
</button>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
name: 'QuasarTooltip',
props: {
modelValue: {
type: String,
required: true
}
},
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
emits: { 'update:modelValue': (payload: string) => payload !== undefined }
})
</script>

View file

@ -1,43 +0,0 @@
import QuasarButton from '../QuasarButton.vue'
describe('QuasarButton', () => {
it('renders a message', () => {
const label = 'Hello there'
cy.mount(QuasarButton, {
props: {
label
}
})
cy.dataCy('button').should('contain', label)
})
it('renders another message', () => {
const label = 'Will this work?'
cy.mount(QuasarButton, {
props: {
label
}
})
cy.dataCy('button').should('contain', label)
})
it('should have a `positive` color', () => {
cy.mount(QuasarButton)
cy.dataCy('button')
.should('have.backgroundColor', 'var(--q-positive)')
.should('have.color', 'white')
})
it('should emit `test` upon click', () => {
cy.mount(QuasarButton)
cy.dataCy('button')
cy.dataCy('button').click()
cy.dataCy('button').should(() => {
expect(Cypress.vueWrapper.emitted('test')).to.have.length(1)
})
})
})

View file

@ -1,38 +0,0 @@
import QuasarCheckComponents from '../QuasarCheckComponents.vue'
describe('QuasarCheckbox', () => {
it('can be used with normal Cypress commands', () => {
cy.mount(QuasarCheckComponents)
cy.dataCy('checkbox').check()
cy.dataCy('checkbox').should('be.checked')
cy.dataCy('checkbox').uncheck()
cy.dataCy('checkbox').should('not.be.checked')
})
})
describe('QuasarToggle', () => {
it('can be used with normal Cypress commands', () => {
cy.mount(QuasarCheckComponents)
cy.dataCy('toggle').check()
cy.dataCy('toggle').should('be.checked')
cy.dataCy('toggle').uncheck()
cy.dataCy('toggle').should('not.be.checked')
})
})
describe('QuasarToggle', () => {
it('can be used with normal Cypress commands', () => {
cy.mount(QuasarCheckComponents)
cy.dataCy('radio-1').check()
cy.dataCy('radio-1').should('be.checked')
cy.dataCy('radio-2').check()
cy.dataCy('radio-2').should('be.checked')
cy.dataCy('radio-1').should('not.be.checked')
})
})

View file

@ -1,22 +0,0 @@
import { Dark } from 'quasar'
import QuasarDark from '../QuasarDark.vue'
describe('QuasarDark', () => {
it('changes its color', () => {
cy.mount(QuasarDark)
cy.dataCy('dark-card')
.should('not.have.class', 'q-dark')
.then(() => {
Dark.set(true)
})
cy.dataCy('dark-card')
.should('have.class', 'q-dark')
.then(() => {
Cypress.vueWrapper.vm.$q.dark.set(false)
})
cy.dataCy('dark-card').should('not.have.class', 'q-dark')
})
})

View file

@ -1,33 +0,0 @@
import QuasarDate from '../QuasarDate.vue'
const targetDate = '2023/02/23'
describe('QuasarDate', () => {
it('selects a date by date string', () => {
cy.mount(QuasarDate)
cy.dataCy('date-picker').selectDate(targetDate)
cy.dataCy('date-value').should('have.text', targetDate)
})
it('selects a date by date object', () => {
cy.mount(QuasarDate)
cy.dataCy('date-picker').selectDate(new Date(targetDate))
cy.dataCy('date-value').should('have.text', targetDate)
})
it('selects a date displayed into a popup proxy', () => {
cy.mount(QuasarDate)
cy.dataCy('open-date-picker-popup-button').click()
cy.withinDialog(() => {
cy.get('.q-date').selectDate(targetDate)
})
cy.dataCy('date-value').should('have.text', targetDate)
// When dealing with a nested dialog, or a popup proxy within a dialog,
// add a data-cy on the dialog/popup-proxy containing the QDate and use the `withinDialog` extended signature:
// Example: cy.withinDialog({ dataCy: 'date-picker-popup', fn: () => { cy.get('.q-date').selectDate(targetDate); } })
})
})

View file

@ -1,42 +0,0 @@
import DialogWrapper from 'app/test/cypress/wrappers/DialogWrapper.vue'
import QuasarDialog from '../QuasarDialog.vue'
describe('QuasarDialog', () => {
it('should show a dialog with a message', () => {
const message = 'Hello, I am a dialog'
cy.mount(DialogWrapper, {
props: {
component: QuasarDialog,
componentProps: {
message
}
}
})
cy.withinDialog((el) => {
cy.wrap(el).should('contain', message)
cy.dataCy('ok-button').click()
})
})
it('should keep the dialog open when not dismissed', () => {
const message = 'Hello, I am a dialog'
cy.mount(DialogWrapper, {
props: {
component: QuasarDialog,
componentProps: {
message
}
}
})
// The helper won't check for the dialog to be closed
// when the callback completes
cy.withinDialog({
persistent: true,
fn: (el) => {
cy.wrap(el).should('contain', message)
}
})
})
})

View file

@ -1,20 +0,0 @@
import LayoutContainer from 'app/test/cypress/wrappers/LayoutContainer.vue'
import QuasarDrawer from '../QuasarDrawer.vue'
describe('QuasarDrawer', () => {
it('should show a drawer', () => {
cy.mount(LayoutContainer, {
props: {
component: QuasarDrawer
}
})
cy.dataCy('drawer')
.should('exist')
.dataCy('button')
.should('not.be.visible')
cy.get('.q-scrollarea .scroll')
cy.get('.q-scrollarea .scroll').scrollTo('bottom', { duration: 500 })
cy.get('.q-scrollarea .scroll').dataCy('button')
cy.get('.q-scrollarea .scroll').should('be.visible')
})
})

View file

@ -1,21 +0,0 @@
import QuasarMenu from '../QuasarMenu.vue'
describe('QuasarMenu', () => {
it('click an item by content', () => {
cy.mount(QuasarMenu)
cy.dataCy('open-menu-btn').click()
cy.withinMenu(() => {
cy.get('.q-item').contains('Item 1').click()
})
})
it('click an item by cardinality', () => {
cy.mount(QuasarMenu)
cy.dataCy('open-menu-btn').click()
cy.withinMenu(() => {
cy.get('.q-item').eq(1).click()
})
})
})

View file

@ -1,21 +0,0 @@
import LayoutContainer from 'app/test/cypress/wrappers/LayoutContainer.vue'
import QuasarPageSticky from '../QuasarPageSticky.vue'
describe('QuasarPageSticky', () => {
it('should show a sticky at the bottom-right of the page', () => {
cy.mount(LayoutContainer, {
props: {
component: QuasarPageSticky,
title: 'Test'
}
})
cy.dataCy('button')
.should('be.visible')
.should(($el) => {
const rect = $el[0].getBoundingClientRect()
expect(rect.bottom).to.equal(window.innerHeight - 18)
expect(rect.right).to.equal(window.innerWidth - 18)
})
})
})

View file

@ -1,44 +0,0 @@
import QuasarSelect from '../QuasarSelect.vue'
function dataCySelect (dataCyId: string) {
return cy.dataCy(dataCyId).closest('.q-select')
}
describe('QuasarSelect', () => {
it('makes sure the select is disabled', () => {
cy.mount(QuasarSelect, {
props: { disable: true }
})
// `cy.dataCy('select')` won't work in this case, as it won't get the root q-select element
dataCySelect('select').should('have.attr', 'aria-disabled', 'true')
})
it('selects an option by content', () => {
cy.mount(QuasarSelect)
cy.dataCy('select').select('Option 1')
cy.dataCy('select-value').should('have.text', 'Option 1')
})
it('selects an option by cardinality', () => {
cy.mount(QuasarSelect)
cy.dataCy('select').select(1)
cy.dataCy('select-value').should('have.text', 'Option 2')
})
it('selects an option asynchronously', () => {
cy.mount(QuasarSelect, {
props: {
loadOptionsAsync: true
}
})
// Wait for loading to complete
cy.dataCy('select').get('.q-spinner').should('not.exist')
cy.dataCy('select').select('Option 3')
cy.dataCy('select-value').should('have.text', 'Option 3')
})
})

View file

@ -1,10 +0,0 @@
import QuasarTooltip from '../QuasarTooltip.vue'
describe('QuasarTooltip', () => {
it('should show a tooltip', () => {
cy.mount(QuasarTooltip)
cy.dataCy('button').trigger('mouseover')
cy.dataCy('tooltip').contains('Here I am!')
})
})

View file

@ -1,72 +0,0 @@
import { vModelAdapter } from '@quasar/quasar-app-extension-testing-e2e-cypress'
import { ref } from 'vue'
import VModelComponent from '../VModelComponent.vue'
describe('VModelComponent', () => {
it('should show the value', () => {
const text = 'Quasar'
cy.mount(VModelComponent, {
props: {
modelValue: text
}
})
cy.dataCy('model-value').should('contain', text)
})
it('should call the listener when an update via inner button occurs', () => {
const text = 'Quasar'
const fn = cy.stub()
cy.mount(VModelComponent, {
props: {
modelValue: text,
// This is how Vue internally codifies listeners,
// defining a prop prepended with `on` and camelCased
'onUpdate:modelValue': fn
}
})
cy.dataCy('button')
cy.dataCy('button').click()
cy.dataCy('button').then(() => {
expect(fn).to.be.calledWith('uasar')
})
})
it('should update the value via inner button when not using the helper', () => {
const text = 'Quasar'
cy.mount(VModelComponent, {
props: {
modelValue: text,
'onUpdate:modelValue': (emittedValue: string) =>
Cypress.vueWrapper.setProps({ modelValue: emittedValue })
}
})
cy.dataCy('button').click()
cy.dataCy('model-value').should('contain', 'uasar')
})
it('should update the value via inner button using the helper', () => {
const model = ref('Quasar')
cy.mount(VModelComponent, {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
props: {
...vModelAdapter(model)
}
})
cy.dataCy('button').click()
cy.dataCy('model-value')
.should('contain', 'uasar')
.then(() => {
// You cannot access `model.value` in a synchronous way,
// you need to chain checks on it to a Cypress command or you'll be testing the initial value.
expect(model.value).to.equal('uasar')
})
})
})

View file

@ -1,12 +0,0 @@
import ColorAssertionsComponent from '../color-assertions.vue'
describe('color assertions', () => {
it('works with names, hex codes and CSS variables', () => {
cy.mount(ColorAssertionsComponent)
cy.get('.wrapper')
.should('have.color', 'var(--q-primary)')
.and('have.backgroundColor', 'black')
.and('have.backgroundColor', '#000')
})
})

View file

@ -1,16 +0,0 @@
import DataCyComponent from '../data-cy.vue'
describe('dataCy command', () => {
it('works as a parent command', () => {
cy.mount(DataCyComponent)
cy.dataCy('wrapper').should('exist')
cy.dataCy('paragraph').should('exist').and('contain', 'Test')
})
it('works as a child command', () => {
cy.mount(DataCyComponent)
cy.dataCy('wrapper').dataCy('paragraph').should('exist')
})
})

View file

@ -1,5 +0,0 @@
<template>
<div class="wrapper text-primary bg-black">
Text1
</div>
</template>

View file

@ -1,7 +0,0 @@
<template>
<div data-cy="wrapper">
<p data-cy="paragraph">
Test
</p>
</div>
</template>

View file

@ -1,38 +0,0 @@
import { installQuasar } from '@quasar/quasar-app-extension-testing-unit-vitest'
import { mount } from '@vue/test-utils'
import { describe, expect, it } from 'vitest'
import ExampleComponent from './demo/ExampleComponent.vue'
installQuasar()
describe('example Component', () => {
it('should mount component with todos', () => {
const wrapper = mount(ExampleComponent, {
props: {
title: 'Hello',
meta: {
totalCount: 4
},
todos: [
{ id: 1, content: 'Hallo' },
{ id: 2, content: 'Hoi' }
]
}
})
expect(wrapper.vm.clickCount).toBe(0)
wrapper.find('.q-item').trigger('click')
expect(wrapper.vm.clickCount).toBe(1)
})
it('should mount component without todos', () => {
const wrapper = mount(ExampleComponent, {
props: {
title: 'Hello',
meta: {
totalCount: 4
}
}
})
expect(wrapper.findAll('.q-item')).toHaveLength(0)
})
})

View file

@ -1,19 +0,0 @@
import { installQuasar } from '@quasar/quasar-app-extension-testing-unit-vitest'
import { mount } from '@vue/test-utils'
import { Notify } from 'quasar'
import { describe, expect, it, vi } from 'vitest'
import NotifyComponent from './demo/NotifyComponent.vue'
installQuasar({ plugins: { Notify } })
describe('notify example', () => {
it('should call notify on click', async () => {
expect(NotifyComponent).toBeTruthy()
const wrapper = mount(NotifyComponent, {})
const spy = vi.spyOn(Notify, 'create')
expect(spy).not.toHaveBeenCalled()
wrapper.trigger('click')
expect(spy).toHaveBeenCalled()
})
})

View file

@ -1,52 +0,0 @@
<template>
<div>
<p>{{ title }}</p>
<q-list>
<q-item
v-for="todo in todos"
:key="todo.id"
clickable
@click="increment"
>
{{ todo.id }} - {{ todo.content }}
</q-item>
</q-list>
<p>Count: {{ todoCount }} / {{ meta.totalCount }}</p>
<p>Active: {{ active ? 'yes' : 'no' }}</p>
<p>Clicks on todos: {{ clickCount }}</p>
</div>
</template>
<script lang="ts" setup>
import { computed, ref } from 'vue'
interface Todo {
id: number;
content: string;
}
interface Meta {
totalCount: number;
}
const props = withDefaults(
defineProps<{
title: string;
todos?: Todo[];
meta: Meta;
active?: boolean;
}>(),
{
todos: () => []
}
)
const clickCount = ref(0)
function increment () {
clickCount.value += 1
return clickCount.value
}
const todoCount = computed(() => props.todos.length)
</script>

View file

@ -1,13 +0,0 @@
<template>
<q-btn @click="onClick">
Click me!
</q-btn>
</template>
<script lang="ts" setup>
import { Notify } from 'quasar'
function onClick () {
Notify.create('Hello there!')
}
</script>