mirror of
https://github.com/Elvanos/fantasia-archive.git
synced 2024-06-16 17:24:53 +12:00
finished integrating component testing + cleanup
This commit is contained in:
parent
53040468db
commit
ea6367bb0f
|
@ -10,7 +10,7 @@
|
|||
"dev:electron": "quasar dev -m electron",
|
||||
"build": "quasar build -m electron --publish never",
|
||||
"test:unit:ui": "vitest --ui",
|
||||
"test:unit:ci": "vitest run",
|
||||
"test:unit:ci": "vitest run --reporter verbose",
|
||||
"test:component": "node \"node_modules/@playwright/test/cli.js\" test src/components/",
|
||||
"test:e2e": "node \"node_modules/@playwright/test/cli.js\" test test/playwright-e2e/"
|
||||
},
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
import { I_extraEnvVariablesAPI } from 'src/interfaces/I_extraEnvVariablesAPI'
|
||||
import appRoot from 'app-root-path'
|
||||
|
||||
export const extraEnvVariablesAPI: I_extraEnvVariablesAPI = {
|
||||
ELECTRON_MAIN_FILEPATH: appRoot + '/dist/electron/UnPackaged/electron-main.js',
|
||||
FA_FRONTEND_RENDER_TIMER: 1000,
|
||||
TEST_ENV: (process.env.TEST_ENV) ? process.env.TEST_ENV : false,
|
||||
COMPONENT_NAME: (process.env.COMPONENT_NAME) ? process.env.COMPONENT_NAME : false
|
||||
}
|
40
src-electron/customContentBridgeAPIs/faWindowControlAPI.ts
Normal file
40
src-electron/customContentBridgeAPIs/faWindowControlAPI.ts
Normal file
|
@ -0,0 +1,40 @@
|
|||
import { BrowserWindow } from '@electron/remote'
|
||||
import { I_faWindowControlAPI } from 'src/interfaces/I_faWindowControlAPI'
|
||||
|
||||
export const faWindowControlAPI: I_faWindowControlAPI = {
|
||||
|
||||
checkWindowMaximized () {
|
||||
const currentWindow = BrowserWindow.getFocusedWindow()
|
||||
if (currentWindow !== null) {
|
||||
return currentWindow.isMaximized()
|
||||
}
|
||||
return false
|
||||
},
|
||||
|
||||
minimizeWindow () {
|
||||
const currentWindow = BrowserWindow.getFocusedWindow()
|
||||
|
||||
if (currentWindow !== null) {
|
||||
currentWindow.minimize()
|
||||
}
|
||||
},
|
||||
|
||||
resizeWindow () {
|
||||
const currentWindow = BrowserWindow.getFocusedWindow()
|
||||
|
||||
if (currentWindow !== null) {
|
||||
if (currentWindow.isMaximized()) {
|
||||
currentWindow.unmaximize()
|
||||
} else {
|
||||
currentWindow.maximize()
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
closeWindow () {
|
||||
const currentWindow = BrowserWindow.getFocusedWindow()
|
||||
if (currentWindow !== null) {
|
||||
currentWindow.close()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -29,44 +29,9 @@
|
|||
*/
|
||||
|
||||
import { contextBridge } from 'electron'
|
||||
import { BrowserWindow } from '@electron/remote'
|
||||
import { I_faWindowControlAPI } from 'src/interfaces/I_faWindowControlAPI'
|
||||
|
||||
const faWindowControlAPI: I_faWindowControlAPI = {
|
||||
|
||||
checkWindowMaximized () {
|
||||
const currentWindow = BrowserWindow.getFocusedWindow()
|
||||
if (currentWindow !== null) {
|
||||
return currentWindow.isMaximized()
|
||||
}
|
||||
return false
|
||||
},
|
||||
minimizeWindow () {
|
||||
const currentWindow = BrowserWindow.getFocusedWindow()
|
||||
|
||||
if (currentWindow !== null) {
|
||||
currentWindow.minimize()
|
||||
}
|
||||
},
|
||||
|
||||
resizeWindow () {
|
||||
const currentWindow = BrowserWindow.getFocusedWindow()
|
||||
|
||||
if (currentWindow !== null) {
|
||||
if (currentWindow.isMaximized()) {
|
||||
currentWindow.unmaximize()
|
||||
} else {
|
||||
currentWindow.maximize()
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
closeWindow () {
|
||||
const currentWindow = BrowserWindow.getFocusedWindow()
|
||||
if (currentWindow !== null) {
|
||||
currentWindow.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
import { faWindowControlAPI } from 'src-electron/customContentBridgeAPIs/faWindowControlAPI'
|
||||
import { extraEnvVariablesAPI } from 'src-electron/customContentBridgeAPIs/extraEnvVariablesAPI'
|
||||
|
||||
contextBridge.exposeInMainWorld('faWindowControlAPI', faWindowControlAPI)
|
||||
contextBridge.exposeInMainWorld('extraEnvVariables', extraEnvVariablesAPI)
|
||||
|
|
33
src/App.vue
33
src/App.vue
|
@ -4,8 +4,39 @@
|
|||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'App'
|
||||
name: 'App',
|
||||
/**
|
||||
* Setup is used to determine if the app is running testing of some kind or in normal mode
|
||||
*/
|
||||
setup () {
|
||||
/**
|
||||
* Local router variable
|
||||
*/
|
||||
const router = useRouter()
|
||||
|
||||
/**
|
||||
* Testing type currently possibly happening
|
||||
* */
|
||||
const testingType = window.extraEnvVariables.TEST_ENV
|
||||
|
||||
/**
|
||||
* Name of the component being possibly tested via component testing
|
||||
* */
|
||||
const testingComponentName = window.extraEnvVariables.COMPONENT_NAME
|
||||
|
||||
/**
|
||||
* In case of some testing happening:
|
||||
* Reroute to the proper component path route assuming all is properly set.
|
||||
* Otherwise, make sure we are on homepage on load.
|
||||
*/
|
||||
if (testingType && testingType === 'components' && testingComponentName) {
|
||||
router.push({ path: `/componentTesting/${testingComponentName}` })
|
||||
} else {
|
||||
router.push({ path: '/' })
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
|
@ -24,6 +24,7 @@ declare module 'vue-i18n' {
|
|||
export default boot(({ app }) => {
|
||||
const i18n = createI18n({
|
||||
locale: 'en-US',
|
||||
fallbackLocale: 'en-US',
|
||||
legacy: false,
|
||||
messages
|
||||
})
|
||||
|
|
|
@ -1,51 +0,0 @@
|
|||
<template>
|
||||
<q-item
|
||||
clickable
|
||||
tag="a"
|
||||
target="_blank"
|
||||
:href="link"
|
||||
>
|
||||
<q-item-section
|
||||
v-if="icon"
|
||||
avatar
|
||||
>
|
||||
<q-icon :name="icon" />
|
||||
</q-item-section>
|
||||
|
||||
<q-item-section>
|
||||
<q-item-label>{{ title }}</q-item-label>
|
||||
<q-item-label caption>
|
||||
{{ caption }}
|
||||
</q-item-label>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'EssentialLink',
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
|
||||
caption: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
|
||||
link: {
|
||||
type: String,
|
||||
default: '#'
|
||||
},
|
||||
|
||||
icon: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
|
@ -1,68 +0,0 @@
|
|||
<template>
|
||||
<div>
|
||||
<p>{{ title }}</p>
|
||||
<ul>
|
||||
<li
|
||||
v-for="todo in todos"
|
||||
:key="todo.id"
|
||||
@click="increment"
|
||||
>
|
||||
{{ todo.id }} - {{ todo.content }}
|
||||
</li>
|
||||
</ul>
|
||||
<p>Count: {{ todoCount }} / {{ meta.totalCount }}</p>
|
||||
<p>Active: {{ active ? 'yes' : 'no' }}</p>
|
||||
<p>Clicks on todos: {{ clickCount }}</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import {
|
||||
defineComponent,
|
||||
PropType,
|
||||
computed,
|
||||
ref,
|
||||
toRef,
|
||||
Ref
|
||||
} from 'vue'
|
||||
import { Todo, Meta } from './models'
|
||||
|
||||
function useClickCount () {
|
||||
const clickCount = ref(0)
|
||||
function increment () {
|
||||
clickCount.value += 1
|
||||
return clickCount.value
|
||||
}
|
||||
|
||||
return { clickCount, increment }
|
||||
}
|
||||
|
||||
function useDisplayTodo (todos: Ref<Todo[]>) {
|
||||
const todoCount = computed(() => todos.value.length)
|
||||
return { todoCount }
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
name: 'ExampleComponent',
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
todos: {
|
||||
type: Array as PropType<Todo[]>,
|
||||
default: () => []
|
||||
},
|
||||
meta: {
|
||||
type: Object as PropType<Meta>,
|
||||
required: true
|
||||
},
|
||||
active: {
|
||||
type: Boolean
|
||||
}
|
||||
},
|
||||
setup (props) {
|
||||
return { ...useClickCount(), ...useDisplayTodo(toRef(props, 'todos')) }
|
||||
}
|
||||
})
|
||||
</script>
|
|
@ -1,88 +1,155 @@
|
|||
import appRoot from 'app-root-path'
|
||||
import { _electron as electron } from 'playwright'
|
||||
import { test, expect } from '@playwright/test'
|
||||
import { extraEnvVariablesAPI } from 'app/src-electron/customContentBridgeAPIs/extraEnvVariablesAPI'
|
||||
|
||||
const electronMainFilePath = appRoot + '/dist/electron/UnPackaged/electron-main.js'
|
||||
const faFrontendRenderTimer = 1000
|
||||
/**
|
||||
* Extra env settings too trigger component testing via Playwright
|
||||
*/
|
||||
const extraEnvSettings = {
|
||||
TEST_ENV: 'components',
|
||||
COMPONENT_NAME: 'GlobalWindowButtons'
|
||||
}
|
||||
|
||||
/**
|
||||
* Electron main filepath
|
||||
*/
|
||||
const electronMainFilePath:string = extraEnvVariablesAPI.ELECTRON_MAIN_FILEPATH
|
||||
|
||||
/**
|
||||
* Extra rended timer buffer for tests to start after loading the app
|
||||
* - Change here in order manually adjust this component's wait times
|
||||
*/
|
||||
const faFrontendRenderTimer:number = extraEnvVariablesAPI.FA_FRONTEND_RENDER_TIMER
|
||||
|
||||
/**
|
||||
* Object of string data selectors for the component
|
||||
*/
|
||||
const selectorList = {
|
||||
buttonMinimize: 'globalWindowButtons-button-minimize',
|
||||
buttonResize: 'globalWindowButtons-button-resize',
|
||||
buttonClose: 'globalWindowButtons-button-close'
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if the Electron launches to begin with.
|
||||
*/
|
||||
test('Should launch app', async () => {
|
||||
const electronApp = await electron.launch({
|
||||
env: extraEnvSettings,
|
||||
args: [electronMainFilePath]
|
||||
})
|
||||
|
||||
test('launch app', async () => {
|
||||
const electronApp = await electron.launch({ args: [electronMainFilePath] })
|
||||
// close app
|
||||
await electronApp.close()
|
||||
})
|
||||
|
||||
test('click resize button - smallify', async () => {
|
||||
const electronApp = await electron.launch({ args: [electronMainFilePath] })
|
||||
/**
|
||||
* Attempt to click the resize button
|
||||
*/
|
||||
test('Click resize button - "smallify"', async () => {
|
||||
const electronApp = await electron.launch({
|
||||
env: extraEnvSettings,
|
||||
args: [electronMainFilePath]
|
||||
})
|
||||
|
||||
const appWindow = await electronApp.firstWindow()
|
||||
await appWindow.waitForTimeout(faFrontendRenderTimer)
|
||||
|
||||
const resizeButton = await appWindow.$('.globalWindowButtons__resize')
|
||||
const resizeButton = await appWindow.$(`[data-test="${selectorList.buttonResize}"]`)
|
||||
|
||||
if (resizeButton !== null) {
|
||||
await resizeButton.click()
|
||||
|
||||
const isMaximized = await appWindow.evaluate(() => window.faWindowControlAPI.checkWindowMaximized())
|
||||
|
||||
expect(isMaximized).toBe(false)
|
||||
} else {
|
||||
test.fail()
|
||||
}
|
||||
|
||||
// close app
|
||||
await electronApp.close()
|
||||
})
|
||||
|
||||
test('click resize button - maximize', async () => {
|
||||
const electronApp = await electron.launch({ args: [electronMainFilePath] })
|
||||
/**
|
||||
* Attempt to click the resize button, twice
|
||||
*/
|
||||
test('Click resize button - "maximize"', async () => {
|
||||
const electronApp = await electron.launch({
|
||||
env: extraEnvSettings,
|
||||
args: [electronMainFilePath]
|
||||
})
|
||||
|
||||
const appWindow = await electronApp.firstWindow()
|
||||
await appWindow.waitForTimeout(faFrontendRenderTimer)
|
||||
|
||||
const resizeButton = await appWindow.$('.globalWindowButtons__resize')
|
||||
const resizeButton = await appWindow.$(`[data-test="${selectorList.buttonResize}"]`)
|
||||
|
||||
if (resizeButton !== null) {
|
||||
// Click twice
|
||||
await resizeButton.click()
|
||||
await resizeButton.click()
|
||||
|
||||
const isMaximized = await appWindow.evaluate(() => window.faWindowControlAPI.checkWindowMaximized())
|
||||
|
||||
expect(isMaximized).toBe(true)
|
||||
} else {
|
||||
test.fail()
|
||||
}
|
||||
|
||||
// close app
|
||||
await electronApp.close()
|
||||
})
|
||||
|
||||
test('click minimize button', async () => {
|
||||
const electronApp = await electron.launch({ args: [electronMainFilePath] })
|
||||
/**
|
||||
* Attempt to click the minimize button
|
||||
*/
|
||||
test('Click minimize button', async () => {
|
||||
const electronApp = await electron.launch({
|
||||
env: extraEnvSettings,
|
||||
args: [electronMainFilePath]
|
||||
})
|
||||
|
||||
const appWindow = await electronApp.firstWindow()
|
||||
await appWindow.waitForTimeout(faFrontendRenderTimer)
|
||||
|
||||
const minimizeButton = await appWindow.$('.globalWindowButtons__minimize')
|
||||
const minimizeButton = await appWindow.$(`[data-test="${selectorList.buttonMinimize}"]`)
|
||||
|
||||
if (minimizeButton !== null) {
|
||||
await minimizeButton.click()
|
||||
|
||||
const isMaximized = await appWindow.evaluate(() => window.faWindowControlAPI.checkWindowMaximized())
|
||||
|
||||
expect(isMaximized).toBe(false)
|
||||
} else {
|
||||
test.fail()
|
||||
}
|
||||
|
||||
// close app
|
||||
await electronApp.close()
|
||||
})
|
||||
|
||||
/* This test can VERY occasionally fail when the window takes too long to close on weaker PCs. Simply rerunning the tests generally fixes this. */
|
||||
test('click close button', async () => {
|
||||
const electronApp = await electron.launch({ args: [electronMainFilePath] })
|
||||
/**
|
||||
* Attempt to click the close button
|
||||
* - This test can VERY occasionally fail when the window takes too long to close on weaker PCs. Simply rerunning the tests generally fixes this.
|
||||
*/
|
||||
test('Click close button', async () => {
|
||||
const electronApp = await electron.launch({
|
||||
env: extraEnvSettings,
|
||||
args: [electronMainFilePath]
|
||||
})
|
||||
|
||||
const appWindow = await electronApp.firstWindow()
|
||||
await appWindow.waitForTimeout(faFrontendRenderTimer)
|
||||
|
||||
const closeButton = await appWindow.$('.globalWindowButtons__close')
|
||||
const closeButton = await appWindow.$(`[data-test="${selectorList.buttonClose}"]`)
|
||||
|
||||
if (closeButton !== null) {
|
||||
let windowIsClosed = false
|
||||
|
||||
// Listen to window close event
|
||||
appWindow.on('close', () => {
|
||||
windowIsClosed = true
|
||||
})
|
||||
|
||||
await closeButton.click()
|
||||
|
||||
expect(windowIsClosed).toBe(true)
|
||||
} else {
|
||||
test.fail()
|
||||
|
|
|
@ -5,24 +5,61 @@ import GlobalWindowButtons from './GlobalWindowButtons.vue'
|
|||
|
||||
installQuasar()
|
||||
|
||||
describe('Unit test - GlobalWindowButtons component', () => {
|
||||
it('should mount three buttons', () => {
|
||||
describe('Component - "GlobalWindowButtons"', () => {
|
||||
/**
|
||||
* Object of string data selectors for the component
|
||||
*/
|
||||
const selectorList = {
|
||||
buttonMinimize: 'globalWindowButtons-button-minimize',
|
||||
buttonResize: 'globalWindowButtons-button-resize',
|
||||
buttonClose: 'globalWindowButtons-button-close'
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if the component has three specific HTML element buttons properly mounted in it:
|
||||
* - Minimize button
|
||||
* - Resize button
|
||||
* - Close button
|
||||
*/
|
||||
it('Wrapper should contain three buttons', () => {
|
||||
const wrapper = mount(GlobalWindowButtons)
|
||||
expect(wrapper.findAll('.q-btn')).toHaveLength(3)
|
||||
|
||||
const buttonList = []
|
||||
|
||||
buttonList.push(wrapper.get(`[data-test="${selectorList.buttonMinimize}"]`))
|
||||
buttonList.push(wrapper.get(`[data-test="${selectorList.buttonResize}"]`))
|
||||
buttonList.push(wrapper.get(`[data-test="${selectorList.buttonClose}"]`))
|
||||
|
||||
expect(buttonList).toHaveLength(3)
|
||||
})
|
||||
|
||||
it('should have `minimize` button', () => {
|
||||
/**
|
||||
* Test if the component has a specific HTML element button properly mounted in it.
|
||||
* - Minimize button
|
||||
*/
|
||||
it('Wrapper should contain "minimize" button', () => {
|
||||
const wrapper = mount(GlobalWindowButtons)
|
||||
expect(wrapper.findAll('.globalWindowButtons__minimize')).toHaveLength(1)
|
||||
|
||||
expect(wrapper.get(`[data-test="${selectorList.buttonMinimize}"]`))
|
||||
})
|
||||
|
||||
it('should have `resize` button', () => {
|
||||
/**
|
||||
* Test if the component has a specific HTML element button properly mounted in it.
|
||||
* - Resize button
|
||||
*/
|
||||
it('Wrapper should contain "resize" button', () => {
|
||||
const wrapper = mount(GlobalWindowButtons)
|
||||
expect(wrapper.findAll('.globalWindowButtons__minimize')).toHaveLength(1)
|
||||
|
||||
expect(wrapper.get(`[data-test="${selectorList.buttonResize}"]`))
|
||||
})
|
||||
|
||||
it('should have `close` button', () => {
|
||||
/**
|
||||
* Test if the component has a specific HTML element button properly mounted in it.
|
||||
* - Close button
|
||||
*/
|
||||
it('Wrapper should contain "close" button', () => {
|
||||
const wrapper = mount(GlobalWindowButtons)
|
||||
expect(wrapper.findAll('.globalWindowButtons__minimize')).toHaveLength(1)
|
||||
|
||||
expect(wrapper.get(`[data-test="${selectorList.buttonClose}"]`))
|
||||
})
|
||||
})
|
||||
|
|
|
@ -11,13 +11,14 @@
|
|||
dark
|
||||
size="xs"
|
||||
class="globalWindowButtons__minimize"
|
||||
data-test="globalWindowButtons-button-minimize"
|
||||
@click="minimizeWindow()"
|
||||
>
|
||||
<q-tooltip
|
||||
:delay="1000"
|
||||
:offset="[0, 5]"
|
||||
>
|
||||
{{ $t('globalWindowButtons_minimizeButton') }}
|
||||
{{ $t('GlobalWindowButtons.minimizeButton') }}
|
||||
</q-tooltip>
|
||||
<q-icon name="mdi-window-minimize" />
|
||||
</q-btn>
|
||||
|
@ -29,13 +30,14 @@
|
|||
dark
|
||||
size="xs"
|
||||
class="globalWindowButtons__resize"
|
||||
data-test="globalWindowButtons-button-resize"
|
||||
@click="[resizeWindow(),checkIfWindowMaximized()]"
|
||||
>
|
||||
<q-tooltip
|
||||
:delay="1000"
|
||||
:offset="[0, 5]"
|
||||
>
|
||||
{{ isMaximized ? $t('globalWindowButtons_resizeButton') : $t('globalWindowButtons_maximizeButton') }}
|
||||
{{ isMaximized ? $t('GlobalWindowButtons.resizeButton') : $t('GlobalWindowButtons.maximizeButton') }}
|
||||
</q-tooltip>
|
||||
<q-icon :name="(isMaximized)? 'mdi-window-restore' : 'mdi-window-maximize'" />
|
||||
</q-btn>
|
||||
|
@ -47,13 +49,14 @@
|
|||
dark
|
||||
size="xs"
|
||||
class="globalWindowButtons__close"
|
||||
data-test="globalWindowButtons-button-close"
|
||||
@click="tryCloseWindow()"
|
||||
>
|
||||
<q-tooltip
|
||||
:delay="1000"
|
||||
:offset="[0, 5]"
|
||||
>
|
||||
{{ $t('globalWindowButtons_close') }}
|
||||
{{ $t('GlobalWindowButtons.close') }}
|
||||
</q-tooltip>
|
||||
<q-icon name="mdi-window-close" />
|
||||
</q-btn>
|
||||
|
@ -64,33 +67,34 @@
|
|||
import { onMounted, ref } from 'vue'
|
||||
import type { Ref } from 'vue'
|
||||
|
||||
/*
|
||||
Triggers minimize of the window by the minimize button click
|
||||
*/
|
||||
/**
|
||||
* Triggers minimize of the window by the minimize button click
|
||||
*/
|
||||
const 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
|
||||
*/
|
||||
/**
|
||||
* Triggers resize of the window by the min/max button click
|
||||
*/
|
||||
const resizeWindow = () => {
|
||||
if (process.env.MODE === 'electron') {
|
||||
window.faWindowControlAPI.resizeWindow()
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Triggers checking of the current app state by the close button click
|
||||
This functionality checks the following:
|
||||
1. If the app has any projects opened to begin with at the moment
|
||||
2. If the project has any pending chnages to it
|
||||
If both is found to be true, then an appropriate dialog is opened
|
||||
Otherwise, the app simply closes
|
||||
*/
|
||||
/**
|
||||
* Triggers checking of the current app state by the close button click.
|
||||
* This functionality checks the following:
|
||||
|
||||
* 1. If the app has any projects opened to begin with at the moment
|
||||
* 2. If the project has any pending chnages to it
|
||||
|
||||
* If both is found to be true, then an appropriate dialog is opened.
|
||||
* Otherwise, the app simply closes.
|
||||
*/
|
||||
const tryCloseWindow = () => {
|
||||
// TODO add project close checking
|
||||
if (process.env.MODE === 'electron') {
|
||||
|
@ -98,8 +102,8 @@ const tryCloseWindow = () => {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Checks if the window is maximized and sets local ref
|
||||
/**
|
||||
Checks if the window is maximized and sets local variable accordingly
|
||||
*/
|
||||
const checkIfWindowMaximized = () => {
|
||||
if (process.env.MODE === 'electron') {
|
||||
|
@ -107,14 +111,14 @@ const checkIfWindowMaximized = () => {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Determines if the window is currently maximized or not
|
||||
*/
|
||||
/**
|
||||
* Determines if the window is currently maximized or not
|
||||
*/
|
||||
const isMaximized: Ref<boolean> = ref(false)
|
||||
|
||||
/*
|
||||
Check on component mount if the windows if maximized or not
|
||||
*/
|
||||
/**
|
||||
* Check on component mount if the windows if maximized or not
|
||||
*/
|
||||
onMounted(() => {
|
||||
checkIfWindowMaximized()
|
||||
})
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
export interface Todo {
|
||||
id: number;
|
||||
content: string;
|
||||
}
|
||||
|
||||
export interface Meta {
|
||||
totalCount: number;
|
||||
}
|
4
src/globals.d.ts
vendored
4
src/globals.d.ts
vendored
|
@ -1,9 +1,11 @@
|
|||
import { I_faWindowControlAPI } from './interfaces/I_faWindowControlAPI'
|
||||
import { I_extraEnvVariablesAPI } from './interfaces/I_extraEnvVariablesAPI'
|
||||
|
||||
export {}
|
||||
|
||||
declare global{
|
||||
interface Window {
|
||||
faWindowControlAPI: I_faWindowControlAPI
|
||||
faWindowControlAPI: I_faWindowControlAPI,
|
||||
extraEnvVariables: I_extraEnvVariablesAPI
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,14 @@
|
|||
// This is just an example,
|
||||
// so you can safely delete all default props below
|
||||
|
||||
export default {
|
||||
appName: 'FA - but in german!'
|
||||
// GLOBAL - APP TEXTS
|
||||
app: {
|
||||
name: 'FA - but in german!'
|
||||
},
|
||||
|
||||
// COMPONENT - GLOBAL WINDOW BUTTONS
|
||||
GlobalWindowButtons: {
|
||||
minimizeButton: 'Minimize',
|
||||
resizeButton: 'Resize Down',
|
||||
maximizeButton: 'Maximize',
|
||||
close: 'Close'
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
// This is just an example,
|
||||
// so you can safely delete all default props below
|
||||
|
||||
export default {
|
||||
appName: 'FA - but in english!',
|
||||
// GLOBAL - APP TEXTS
|
||||
app: {
|
||||
name: 'FA - but in english!'
|
||||
},
|
||||
|
||||
// COMPONENT - GLOBAL WINDOW BUTTONS
|
||||
globalWindowButtons_minimizeButton: 'Minimize',
|
||||
globalWindowButtons_resizeButton: 'Resize Down',
|
||||
globalWindowButtons_maximizeButton: 'Maximize',
|
||||
globalWindowButtons_close: 'Close'
|
||||
GlobalWindowButtons: {
|
||||
minimizeButton: 'Minimize',
|
||||
resizeButton: 'Resize Down',
|
||||
maximizeButton: 'Maximize',
|
||||
close: 'Close'
|
||||
}
|
||||
}
|
||||
|
|
27
src/interfaces/I_extraEnvVariablesAPI.ts
Normal file
27
src/interfaces/I_extraEnvVariablesAPI.ts
Normal file
|
@ -0,0 +1,27 @@
|
|||
export interface I_extraEnvVariablesAPI {
|
||||
|
||||
/**
|
||||
* Full path to "electron-main.js" file in the dist, unpackaged form
|
||||
*/
|
||||
ELECTRON_MAIN_FILEPATH: string
|
||||
|
||||
/**
|
||||
* Extra rended timer buffer for tests to start after loading the app.
|
||||
* - Increase if your machine isn't keeping up with the render times and tests are randomly failing.
|
||||
* - Lower if your machine is quick and the tests are waiting for no reason at all.
|
||||
* - Can be set manually for each component/e2e test inside the test file.
|
||||
*/
|
||||
FA_FRONTEND_RENDER_TIMER: number
|
||||
|
||||
/**
|
||||
* Type of test environment to load.
|
||||
*/
|
||||
TEST_ENV?: 'components'|'e2e'|false
|
||||
|
||||
/**
|
||||
* Name of the component being tested.
|
||||
* - MUST match the file name of the vue file being tested (including the capital letter at the start).
|
||||
*/
|
||||
COMPONENT_NAME?: string|false
|
||||
|
||||
}
|
|
@ -1,6 +1,25 @@
|
|||
export interface I_faWindowControlAPI {
|
||||
|
||||
/**
|
||||
* Check the current visual sizing of the current window
|
||||
*/
|
||||
checkWindowMaximized: () => boolean
|
||||
|
||||
/**
|
||||
* Minimizes the current window
|
||||
*/
|
||||
minimizeWindow: () => void
|
||||
|
||||
/**
|
||||
* Resizes the current window.
|
||||
* - If the window is maximized, smallifies it
|
||||
* - If the window is smallified, maximizes it
|
||||
*/
|
||||
resizeWindow: () => void
|
||||
|
||||
/**
|
||||
* Closes the current window
|
||||
*/
|
||||
closeWindow: () => void
|
||||
|
||||
}
|
||||
|
|
15
src/layouts/ComponentTestingLayout.vue
Normal file
15
src/layouts/ComponentTestingLayout.vue
Normal file
|
@ -0,0 +1,15 @@
|
|||
<template>
|
||||
<q-layout>
|
||||
<q-page-container>
|
||||
<router-view :key="$route.path" />
|
||||
</q-page-container>
|
||||
</q-layout>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'ComponentTestingLayout'
|
||||
})
|
||||
</script>
|
|
@ -13,7 +13,7 @@
|
|||
/>
|
||||
|
||||
<q-toolbar-title>
|
||||
{{ $t('appName') }}
|
||||
{{ $t('app.name') }}
|
||||
</q-toolbar-title>
|
||||
|
||||
<div>Quasar v{{ $q.version }}</div>
|
||||
|
@ -31,12 +31,6 @@
|
|||
>
|
||||
Essential Links
|
||||
</q-item-label>
|
||||
|
||||
<EssentialLink
|
||||
v-for="link in essentialLinks"
|
||||
:key="link.title"
|
||||
v-bind="link"
|
||||
/>
|
||||
</q-list>
|
||||
</q-drawer>
|
||||
|
||||
|
@ -48,58 +42,12 @@
|
|||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref } from 'vue'
|
||||
import EssentialLink from 'components/EssentialLink.vue'
|
||||
import GlobalWindowButtons from 'components/GlobalWindowButtons/GlobalWindowButtons.vue'
|
||||
const linksList = [
|
||||
{
|
||||
title: 'Docs',
|
||||
caption: 'quasar.dev',
|
||||
icon: 'school',
|
||||
link: 'https://quasar.dev'
|
||||
},
|
||||
{
|
||||
title: 'Github',
|
||||
caption: 'github.com/quasarframework',
|
||||
icon: 'code',
|
||||
link: 'https://github.com/quasarframework'
|
||||
},
|
||||
{
|
||||
title: 'Discord Chat Channel',
|
||||
caption: 'chat.quasar.dev',
|
||||
icon: 'chat',
|
||||
link: 'https://chat.quasar.dev'
|
||||
},
|
||||
{
|
||||
title: 'Forum',
|
||||
caption: 'forum.quasar.dev',
|
||||
icon: 'record_voice_over',
|
||||
link: 'https://forum.quasar.dev'
|
||||
},
|
||||
{
|
||||
title: 'Twitter',
|
||||
caption: '@quasarframework',
|
||||
icon: 'rss_feed',
|
||||
link: 'https://twitter.quasar.dev'
|
||||
},
|
||||
{
|
||||
title: 'Facebook',
|
||||
caption: '@QuasarFramework',
|
||||
icon: 'public',
|
||||
link: 'https://facebook.quasar.dev'
|
||||
},
|
||||
{
|
||||
title: 'Quasar Awesome',
|
||||
caption: 'Community Quasar projects',
|
||||
icon: 'favorite',
|
||||
link: 'https://awesome.quasar.dev'
|
||||
}
|
||||
]
|
||||
|
||||
export default defineComponent({
|
||||
name: 'MainLayout',
|
||||
|
||||
components: {
|
||||
EssentialLink,
|
||||
GlobalWindowButtons
|
||||
},
|
||||
|
||||
|
@ -107,7 +55,6 @@ export default defineComponent({
|
|||
const leftDrawerOpen = ref(false)
|
||||
|
||||
return {
|
||||
essentialLinks: linksList,
|
||||
leftDrawerOpen,
|
||||
toggleLeftDrawer () {
|
||||
leftDrawerOpen.value = !leftDrawerOpen.value
|
||||
|
|
47
src/pages/ComponentTesting.vue
Normal file
47
src/pages/ComponentTesting.vue
Normal file
|
@ -0,0 +1,47 @@
|
|||
<template>
|
||||
<q-page class="row items-center justify-evenly">
|
||||
<component :is="currentComponent" />
|
||||
</q-page>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useRoute } from 'vue-router'
|
||||
|
||||
/**
|
||||
* Current route
|
||||
*/
|
||||
const route = useRoute()
|
||||
|
||||
/**
|
||||
* Currently tested component's name based on the last part of the route
|
||||
*/
|
||||
const componentName = route.params.componentName
|
||||
|
||||
/**
|
||||
* Auto-import all components from the automatic matching via the route path
|
||||
*/
|
||||
const componentList = import.meta.globEager('components/**/*.vue')
|
||||
|
||||
/**
|
||||
* Placeholder variable for the matched component
|
||||
*/
|
||||
let currentComponent = null as unknown
|
||||
|
||||
/**
|
||||
* Loops through the component list
|
||||
*/
|
||||
for (const loopPath in componentList) {
|
||||
/**
|
||||
* Current component from the loop
|
||||
*/
|
||||
const loopComponent = componentList[loopPath].default
|
||||
|
||||
/**
|
||||
* If the route-component-name matches the name of component in the loop, load it as the curently displayed one
|
||||
*/
|
||||
if (loopComponent.__name === componentName) {
|
||||
currentComponent = loopComponent
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
|
@ -1,49 +1,12 @@
|
|||
<template>
|
||||
<q-page class="row items-center justify-evenly">
|
||||
<example-component
|
||||
title="Example component"
|
||||
active
|
||||
:todos="todos"
|
||||
:meta="meta"
|
||||
/>
|
||||
</q-page>
|
||||
<q-page class="row items-center justify-evenly" />
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Todo, Meta } from 'components/models'
|
||||
import ExampleComponent from 'components/ExampleComponent.vue'
|
||||
import { defineComponent, ref } from 'vue'
|
||||
import { defineComponent } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'IndexPage',
|
||||
components: { ExampleComponent },
|
||||
setup () {
|
||||
const todos = ref<Todo[]>([
|
||||
{
|
||||
id: 1,
|
||||
content: 'ct1'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
content: 'ct2'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
content: 'ct3'
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
content: 'ct4'
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
content: 'ct5'
|
||||
}
|
||||
])
|
||||
const meta = ref<Meta>({
|
||||
totalCount: 1200
|
||||
})
|
||||
return { todos, meta }
|
||||
}
|
||||
components: {}
|
||||
})
|
||||
</script>
|
||||
|
|
|
@ -1,14 +1,30 @@
|
|||
import { RouteRecordRaw } from 'vue-router'
|
||||
|
||||
const routes: RouteRecordRaw[] = [
|
||||
|
||||
/**
|
||||
* Default pathing
|
||||
*/
|
||||
{
|
||||
path: '/',
|
||||
component: () => import('layouts/MainLayout.vue'),
|
||||
children: [{ path: '', component: () => import('pages/IndexPage.vue') }]
|
||||
},
|
||||
|
||||
// Always leave this as last one,
|
||||
// but you can also remove it
|
||||
/**
|
||||
* Component testing pathing
|
||||
*/
|
||||
{
|
||||
path: '/componentTesting/:componentName',
|
||||
component: () => import('layouts/ComponentTestingLayout.vue'),
|
||||
children: [
|
||||
{ path: '', component: () => import('pages/ComponentTesting.vue') }
|
||||
]
|
||||
},
|
||||
|
||||
/**
|
||||
* Always leave this as last one, but you can also remove it
|
||||
*/
|
||||
{
|
||||
path: '/:catchAll(.*)*',
|
||||
component: () => import('pages/ErrorNotFound.vue')
|
||||
|
|
|
@ -1,90 +0,0 @@
|
|||
import appRoot from 'app-root-path'
|
||||
import { _electron as electron } from 'playwright'
|
||||
import { test, expect } from '@playwright/test'
|
||||
|
||||
const electronMainFilePath = appRoot + '/dist/electron/UnPackaged/electron-main.js'
|
||||
const faFrontendRenderTimer = 1000
|
||||
|
||||
test('launch app', async () => {
|
||||
const electronApp = await electron.launch({ args: [electronMainFilePath] })
|
||||
// close app
|
||||
await electronApp.close()
|
||||
})
|
||||
|
||||
test('click resize button - smallify', async () => {
|
||||
const electronApp = await electron.launch({ args: [electronMainFilePath] })
|
||||
const appWindow = await electronApp.firstWindow()
|
||||
await appWindow.waitForTimeout(faFrontendRenderTimer)
|
||||
|
||||
const resizeButton = await appWindow.$('.globalWindowButtons__resize')
|
||||
|
||||
if (resizeButton !== null) {
|
||||
await resizeButton.click()
|
||||
const isMaximized = await appWindow.evaluate(() => window.faWindowControlAPI.checkWindowMaximized())
|
||||
expect(isMaximized).toBe(false)
|
||||
} else {
|
||||
test.fail()
|
||||
}
|
||||
|
||||
// close app
|
||||
await electronApp.close()
|
||||
})
|
||||
|
||||
test('click resize button - maximize', async () => {
|
||||
const electronApp = await electron.launch({ args: [electronMainFilePath] })
|
||||
const appWindow = await electronApp.firstWindow()
|
||||
await appWindow.waitForTimeout(faFrontendRenderTimer)
|
||||
|
||||
const resizeButton = await appWindow.$('.globalWindowButtons__resize')
|
||||
|
||||
if (resizeButton !== null) {
|
||||
await resizeButton.click()
|
||||
await resizeButton.click()
|
||||
const isMaximized = await appWindow.evaluate(() => window.faWindowControlAPI.checkWindowMaximized())
|
||||
expect(isMaximized).toBe(true)
|
||||
} else {
|
||||
test.fail()
|
||||
}
|
||||
|
||||
// close app
|
||||
await electronApp.close()
|
||||
})
|
||||
|
||||
test('click minimize button', async () => {
|
||||
const electronApp = await electron.launch({ args: [electronMainFilePath] })
|
||||
const appWindow = await electronApp.firstWindow()
|
||||
await appWindow.waitForTimeout(faFrontendRenderTimer)
|
||||
|
||||
const minimizeButton = await appWindow.$('.globalWindowButtons__minimize')
|
||||
|
||||
if (minimizeButton !== null) {
|
||||
await minimizeButton.click()
|
||||
const isMaximized = await appWindow.evaluate(() => window.faWindowControlAPI.checkWindowMaximized())
|
||||
expect(isMaximized).toBe(false)
|
||||
} else {
|
||||
test.fail()
|
||||
}
|
||||
|
||||
// close app
|
||||
await electronApp.close()
|
||||
})
|
||||
|
||||
/* This test can VERY occasionally fail when the window takes too long to close on weaker PCs. Simply rerunning the tests generally fixes this. */
|
||||
test('click close button', async () => {
|
||||
const electronApp = await electron.launch({ args: [electronMainFilePath] })
|
||||
const appWindow = await electronApp.firstWindow()
|
||||
await appWindow.waitForTimeout(faFrontendRenderTimer)
|
||||
|
||||
const closeButton = await appWindow.$('.globalWindowButtons__close')
|
||||
|
||||
if (closeButton !== null) {
|
||||
let windowIsClosed = false
|
||||
appWindow.on('close', () => {
|
||||
windowIsClosed = true
|
||||
})
|
||||
await closeButton.click()
|
||||
expect(windowIsClosed).toBe(true)
|
||||
} else {
|
||||
test.fail()
|
||||
}
|
||||
})
|
1
test/playwright-e2e/someTest.spec.ts
Normal file
1
test/playwright-e2e/someTest.spec.ts
Normal file
|
@ -0,0 +1 @@
|
|||
// TODO ADD SOME TESTS
|
Loading…
Reference in a new issue