0
0
Fork 0

Removed editor settings and eslint formatter

This commit is contained in:
Joan Sanchez 2022-03-14 11:31:37 +01:00
parent cbfcb237eb
commit 69728b32cb
48 changed files with 2847 additions and 469 deletions

View File

@ -80,7 +80,7 @@ module.exports = {
// TypeScript // TypeScript
quotes: ['warn', 'single', { avoidEscape: true }], quotes: ['warn', 'single', { avoidEscape: true }],
'@typescript-eslint/explicit-function-return-type': 'off', '@typescript-eslint/explicit-function-return-type': 'off',
"@typescript-eslint/unbound-method": "off", '@typescript-eslint/unbound-method': 'off',
'@typescript-eslint/no-unsafe-assignment': 'off', '@typescript-eslint/no-unsafe-assignment': 'off',
'@typescript-eslint/no-unsafe-member-access': 'off', '@typescript-eslint/no-unsafe-member-access': 'off',

1
.gitignore vendored
View File

@ -3,7 +3,6 @@
node_modules node_modules
# Quasar core related directories # Quasar core related directories
.quasar
/dist /dist
# Cordova related directories and files # Cordova related directories and files

39
.quasar/app.js Normal file
View File

@ -0,0 +1,39 @@
/**
* THIS FILE IS GENERATED AUTOMATICALLY.
* DO NOT EDIT.
*
* You are probably looking on adding startup/initialization code.
* Use "quasar new boot <name>" and add it there.
* One boot file per concern. Then reference the file(s) in quasar.conf.js > boot:
* boot: ['file', ...] // do not add ".js" extension to it.
*
* Boot files are your "main.js"
**/
import { Quasar } from 'quasar';
import RootComponent from 'app/src/App.vue';
import createRouter from 'app/src/router/index';
export default async function (createAppFn, quasarUserOptions) {
// create store and router instances
const router = typeof createRouter === 'function' ? await createRouter({}) : createRouter;
// Create the app instance.
// Here we inject into it the Quasar UI, the router & possibly the store.
const app = createAppFn(RootComponent);
app.config.devtools = true;
app.use(Quasar, quasarUserOptions);
// Expose the app, the router and the store.
// Note that we are not mounting the app here, since bootstrapping will be
// different depending on whether we are in a browser or on the server.
return {
app,
router,
};
}

100
.quasar/client-entry.js Normal file
View File

@ -0,0 +1,100 @@
/**
* THIS FILE IS GENERATED AUTOMATICALLY.
* DO NOT EDIT.
*
* You are probably looking on adding startup/initialization code.
* Use "quasar new boot <name>" and add it there.
* One boot file per concern. Then reference the file(s) in quasar.conf.js > boot:
* boot: ['file', ...] // do not add ".js" extension to it.
*
* Boot files are your "main.js"
**/
import { createApp } from 'vue';
import '@quasar/extras/roboto-font/roboto-font.css';
import '@quasar/extras/material-icons/material-icons.css';
// We load Quasar stylesheet file
import 'quasar/dist/quasar.sass';
import 'src/css/app.scss';
import createQuasarApp from './app.js';
import quasarUserOptions from './quasar-user-options.js';
console.info('[Quasar] Running SPA.');
const publicPath = ``;
async function start({ app, router }, bootFiles) {
let hasRedirected = false;
const getRedirectUrl = (url) => {
try {
return router.resolve(url).href;
} catch (err) {}
return Object(url) === url ? null : url;
};
const redirect = (url) => {
hasRedirected = true;
if (typeof url === 'string' && /^https?:\/\//.test(url)) {
window.location.href = url;
return;
}
const href = getRedirectUrl(url);
// continue if we didn't fail to resolve the url
if (href !== null) {
window.location.href = href;
window.location.reload();
}
};
const urlPath = window.location.href.replace(window.location.origin, '');
for (let i = 0; hasRedirected === false && i < bootFiles.length; i++) {
try {
await bootFiles[i]({
app,
router,
ssrContext: null,
redirect,
urlPath,
publicPath,
});
} catch (err) {
if (err && err.url) {
redirect(err.url);
return;
}
console.error('[Quasar] boot error:', err);
return;
}
}
if (hasRedirected === true) {
return;
}
app.use(router);
app.mount('#q-app');
}
createQuasarApp(createApp, quasarUserOptions).then((app) => {
return Promise.all([
import(/* webpackMode: "eager" */ 'boot/i18n'),
import(/* webpackMode: "eager" */ 'boot/axios'),
]).then((bootFiles) => {
const boot = bootFiles.map((entry) => entry.default).filter((entry) => typeof entry === 'function');
start(app, boot);
});
});

113
.quasar/client-prefetch.js Normal file
View File

@ -0,0 +1,113 @@
/**
* THIS FILE IS GENERATED AUTOMATICALLY.
* DO NOT EDIT.
*
* You are probably looking on adding startup/initialization code.
* Use "quasar new boot <name>" and add it there.
* One boot file per concern. Then reference the file(s) in quasar.conf.js > boot:
* boot: ['file', ...] // do not add ".js" extension to it.
*
* Boot files are your "main.js"
**/
import App from 'app/src/App.vue';
let appPrefetch =
typeof App.preFetch === 'function'
? App.preFetch
: // Class components return the component options (and the preFetch hook) inside __c property
App.__c !== void 0 && typeof App.__c.preFetch === 'function'
? App.__c.preFetch
: false;
function getMatchedComponents(to, router) {
const route = to ? (to.matched ? to : router.resolve(to).route) : router.currentRoute;
if (!route) {
return [];
}
return Array.prototype.concat.apply(
[],
route.matched.map((m) => {
return Object.keys(m.components).map((key) => {
const comp = m.components[key];
return {
path: m.path,
c: comp,
};
});
})
);
}
export function addPreFetchHooks(router, publicPath) {
// Add router hook for handling preFetch.
// Doing it after initial route is resolved so that we don't double-fetch
// the data that we already have. Using router.beforeResolve() so that all
// async components are resolved.
router.beforeResolve((to, from, next) => {
const urlPath = window.location.href.replace(window.location.origin, ''),
matched = getMatchedComponents(to, router),
prevMatched = getMatchedComponents(from, router);
let diffed = false;
const preFetchList = matched
.filter((m, i) => {
return (
diffed ||
(diffed =
!prevMatched[i] || prevMatched[i].c !== m.c || m.path.indexOf('/:') > -1) // does it has params?
);
})
.filter(
(m) =>
m.c !== void 0 &&
(typeof m.c.preFetch === 'function' ||
// Class components return the component options (and the preFetch hook) inside __c property
(m.c.__c !== void 0 && typeof m.c.__c.preFetch === 'function'))
)
.map((m) => (m.c.__c !== void 0 ? m.c.__c.preFetch : m.c.preFetch));
if (appPrefetch !== false) {
preFetchList.unshift(appPrefetch);
appPrefetch = false;
}
if (preFetchList.length === 0) {
return next();
}
let hasRedirected = false;
const redirect = (url) => {
hasRedirected = true;
next(url);
};
const proceed = () => {
if (hasRedirected === false) {
next();
}
};
preFetchList
.reduce(
(promise, preFetch) =>
promise.then(
() =>
hasRedirected === false &&
preFetch({
currentRoute: to,
previousRoute: from,
redirect,
urlPath,
publicPath,
})
),
Promise.resolve()
)
.then(proceed)
.catch((e) => {
console.error(e);
proceed();
});
});
}

View File

@ -0,0 +1,15 @@
/**
* THIS FILE IS GENERATED AUTOMATICALLY.
* DO NOT EDIT.
*
* You are probably looking on adding startup/initialization code.
* Use "quasar new boot <name>" and add it there.
* One boot file per concern. Then reference the file(s) in quasar.conf.js > boot:
* boot: ['file', ...] // do not add ".js" extension to it.
*
* Boot files are your "main.js"
**/
import { Notify } from 'quasar';
export default { config: {}, plugins: { Notify } };

View File

@ -1,15 +0,0 @@
{
"recommendations": [
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"editorconfig.editorconfig",
"johnsoncodehk.volar",
"wayou.vscode-todo-highlight"
],
"unwantedRecommendations": [
"octref.vetur",
"hookyqr.beautify",
"dbaeumer.jshint",
"ms-vscode.vscode-typescript-tslint-plugin"
]
}

47
.vscode/settings.json vendored
View File

@ -1,42 +1,7 @@
{ {
"editor.bracketPairColorization.enabled": true, "editor.bracketPairColorization.enabled": true,
"editor.guides.bracketPairs": true, "editor.guides.bracketPairs": true,
"editor.formatOnSave": true, "editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode", "editor.codeActionsOnSave": ["source.fixAll.eslint"],
"editor.codeActionsOnSave": [ "eslint.validate": ["javascript", "javascriptreact", "typescript", "vue"]
"source.fixAll.eslint" }
],
"eslint.validate": [
"javascript",
"javascriptreact",
"typescript",
"vue"
],
"typescript.tsdk": "node_modules/typescript/lib",
"[typescript]": {
"editor.defaultFormatter": "vscode.typescript-language-features"
},
"[jsonc]": {
"editor.defaultFormatter": "vscode.json-language-features"
},
"[json]": {
"editor.defaultFormatter": "vscode.json-language-features"
},
"[javascript]": {
"editor.defaultFormatter": "vscode.typescript-language-features"
},
"[vue]": {
"editor.defaultFormatter": "johnsoncodehk.volar"
},
"[html]": {
"editor.defaultFormatter": "vscode.html-language-features"
},
"json.schemas": [
{
"fileMatch": [
"cypress.json"
],
"url": "https://on.cypress.io/cypress.schema.json"
}
]
}

View File

@ -12,4 +12,4 @@
"testFiles": "**/*.spec.js", "testFiles": "**/*.spec.js",
"supportFile": "test/cypress/support/unit.js" "supportFile": "test/cypress/support/unit.js"
} }
} }

View File

@ -74,8 +74,7 @@ module.exports = {
// (sync) .babelrc, .babelrc.js, babel.config.js, package.json // (sync) .babelrc, .babelrc.js, babel.config.js, package.json
// https://github.com/tleunen/find-babel-config/issues/33 // https://github.com/tleunen/find-babel-config/issues/33
'.*\\.vue$': 'vue-jest', '.*\\.vue$': 'vue-jest',
'.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$': '.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$': 'jest-transform-stub',
'jest-transform-stub',
}, },
transformIgnorePatterns: [`node_modules/(?!(${esModules}))`], transformIgnorePatterns: [`node_modules/(?!(${esModules}))`],
snapshotSerializers: ['<rootDir>/node_modules/jest-serializer-vue'], snapshotSerializers: ['<rootDir>/node_modules/jest-serializer-vue'],

View File

@ -57,4 +57,4 @@
"npm": ">= 6.13.4", "npm": ">= 6.13.4",
"yarn": ">= 1.21.1" "yarn": ">= 1.21.1"
} }
} }

View File

@ -1,14 +1,9 @@
{ {
"@quasar/testing-unit-jest": { "@quasar/testing-unit-jest": {
"babel": "babelrc", "babel": "babelrc",
"options": [ "options": ["scripts", "typescript"]
"scripts",
"typescript"
]
}, },
"@quasar/testing-e2e-cypress": { "@quasar/testing-e2e-cypress": {
"options": [ "options": ["scripts"]
"scripts"
]
} }
} }

View File

@ -8,4 +8,4 @@
"unit-cypress": { "unit-cypress": {
"runnerCommand": "cypress run-ct" "runnerCommand": "cypress run-ct"
} }
} }

View File

@ -4,7 +4,6 @@ import axios, { AxiosInstance } from 'axios';
import { useSession } from 'src/composables/useSession'; import { useSession } from 'src/composables/useSession';
const { getToken } = useSession(); const { getToken } = useSession();
declare module '@vue/runtime-core' { declare module '@vue/runtime-core' {
interface ComponentCustomProperties { interface ComponentCustomProperties {
$axios: AxiosInstance; $axios: AxiosInstance;
@ -34,7 +33,6 @@ axios.interceptors.request.use(
} }
); );
export default boot(({ app }) => { export default boot(({ app }) => {
// for use inside Vue files (Options API) through this.$axios and this.$api // for use inside Vue files (Options API) through this.$axios and this.$api

View File

@ -13,4 +13,4 @@ export default boot(({ app }) => {
app.use(i18n); app.use(i18n);
}); });
export { i18n }; export { i18n };

View File

@ -1,7 +1,7 @@
<template> <template>
<q-header class="bg-dark" color="white" elevated bordered> <q-header class="bg-dark" color="white" elevated bordered>
<q-toolbar class="q-py-sm q-px-md"> <q-toolbar class="q-py-sm q-px-md">
<q-btn flat @click="$emit('on-toggle-drawer')" round dense icon="menu" /> <q-btn flat @click="$emit('toggle-drawer')" round dense icon="menu" />
<router-link to="/"> <router-link to="/">
<q-btn flat round class="q-ml-xs" v-if="$q.screen.gt.xs"> <q-btn flat round class="q-ml-xs" v-if="$q.screen.gt.xs">
<q-avatar square size="md"> <q-avatar square size="md">
@ -51,4 +51,8 @@ const session = useSession();
const state = useState(); const state = useState();
const user = state.getUser(); const user = state.getUser();
const token = session.getToken(); const token = session.getToken();
defineEmits<{
(event: 'toggle-drawer'): void;
}>();
</script> </script>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -11,12 +11,7 @@
true-value="en" true-value="en"
v-model="locale" v-model="locale"
/> />
<q-toggle <q-toggle v-model="darkMode" checked-icon="dark_mode" color="orange" unchecked-icon="light_mode" />
v-model="darkMode"
checked-icon="dark_mode"
color="orange"
unchecked-icon="light_mode"
/>
<q-btn color="orange" outline size="sm" label="Settings" icon="settings" /> <q-btn color="orange" outline size="sm" label="Settings" icon="settings" />
</div> </div>
@ -36,15 +31,7 @@
</div> </div>
<div class="text-subtitle3 text-grey-7 q-mb-xs">@{{ user.username }}</div> <div class="text-subtitle3 text-grey-7 q-mb-xs">@{{ user.username }}</div>
<q-btn <q-btn color="orange" flat label="Log Out" size="sm" icon="logout" @click="logout()" v-close-popup />
color="orange"
flat
label="Log Out"
size="sm"
icon="logout"
@click="logout()"
v-close-popup
/>
</div> </div>
</div> </div>
</q-menu> </q-menu>

View File

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

View File

@ -3,22 +3,22 @@ import DialogWrapper from 'app/test/cypress/wrappers/DialogWrapper.vue';
import QuasarDialog from '../QuasarDialog.vue'; import QuasarDialog from '../QuasarDialog.vue';
describe('QuasarDialog', () => { describe('QuasarDialog', () => {
it('should show a dialog with a message', () => { it('should show a dialog with a message', () => {
const message = 'Hello, I am a dialog'; const message = 'Hello, I am a dialog';
mount(DialogWrapper, { mount(DialogWrapper, {
props: { props: {
component: QuasarDialog, component: QuasarDialog,
componentProps: { componentProps: {
message, message,
}, },
}, },
});
cy.dataCy('dialog').should('exist').should('contain', message);
}); });
cy.dataCy('dialog').should('exist').should('contain', message);
});
it('should close a dialog when clikcing ok', () => { it('should close a dialog when clikcing ok', () => {
// The dialog is still visible from the previous test // The dialog is still visible from the previous test
cy.dataCy('dialog').should('exist').dataCy('ok-button').click(); cy.dataCy('dialog').should('exist').dataCy('ok-button').click();
cy.dataCy('dialog').should('not.exist'); cy.dataCy('dialog').should('not.exist');
}); });
}); });

View File

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

View File

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

View File

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

View File

@ -15,4 +15,4 @@ export function useRole() {
hasAny, hasAny,
}; };
} }
*/ */

View File

@ -1,2 +1,2 @@
// app global css in SCSS form // app global css in SCSS form
@import './icons.scss'; @import './icons.scss';

File diff suppressed because one or more lines are too long

View File

@ -1,35 +1,35 @@
export default { export default {
globals: { globals: {
lang: { lang: {
'es': 'Spanish', es: 'Spanish',
'en': 'English' en: 'English',
} },
}, },
errors: { errors: {
'statusUnauthorized': 'Access denied', statusUnauthorized: 'Access denied',
'statusInternalServerError': 'An internal server error has ocurred' statusInternalServerError: 'An internal server error has ocurred',
}, },
login: { login: {
'title': 'Login', title: 'Login',
'username': 'Username', username: 'Username',
'password': 'Password', password: 'Password',
'submit': 'Log in', submit: 'Log in',
'keepLogin': 'Keep me logged in', keepLogin: 'Keep me logged in',
'loginSuccess': 'You have successfully logged in', loginSuccess: 'You have successfully logged in',
'loginError': 'Invalid username or password' loginError: 'Invalid username or password',
}, },
customer: {}, customer: {},
components: { components: {
'topbar': {}, topbar: {},
'userPanel': { userPanel: {
'settings': 'Settings', settings: 'Settings',
'logOut': 'Log Out' logOut: 'Log Out',
} },
}, },
pages: { pages: {
'logIn': 'Log In', logIn: 'Log In',
'dashboard': 'Dashboard', dashboard: 'Dashboard',
'customers': 'Customers', customers: 'Customers',
'list': 'List', list: 'List',
} },
}; };

View File

@ -1,29 +1,29 @@
export default { export default {
'globals': { globals: {
'lang': { lang: {
'es': 'Español', es: 'Español',
'en': 'Inglés' en: 'Inglés',
} },
}, },
'errors': { errors: {
'statusUnauthorized': 'Acceso denegado', statusUnauthorized: 'Acceso denegado',
'statusInternalServerError': 'Ha ocurrido un error interno del servidor' statusInternalServerError: 'Ha ocurrido un error interno del servidor',
}, },
'login': { login: {
'title': 'Iniciar sesión', title: 'Iniciar sesión',
'username': 'Nombre de usuario', username: 'Nombre de usuario',
'password': 'Contraseña', password: 'Contraseña',
'submit': 'Iniciar sesión', submit: 'Iniciar sesión',
'keepLogin': 'Mantener sesión iniciada', keepLogin: 'Mantener sesión iniciada',
'loginSuccess': 'Inicio de sesión correcto', loginSuccess: 'Inicio de sesión correcto',
'loginError': 'Nombre de usuario o contraseña incorrectos' loginError: 'Nombre de usuario o contraseña incorrectos',
}, },
'customer': {}, customer: {},
'components': { components: {
'topbar': {}, topbar: {},
'userPanel': { userPanel: {
'settings': 'Configuración', settings: 'Configuración',
'logOut': 'Cerrar sesión' logOut: 'Cerrar sesión',
} },
} },
} };

View File

@ -2,6 +2,6 @@ import en from './en';
import es from './es'; import es from './es';
export default { export default {
'en': en, en: en,
'es': es, es: es,
}; };

View File

@ -1,28 +1,26 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head>
<title><%= productName %></title>
<head> <meta charset="utf-8" />
<title> <meta name="description" content="<%= productDescription %>" />
<%= productName %> <meta name="format-detection" content="telephone=no" />
</title> <meta name="msapplication-tap-highlight" content="no" />
<meta
name="viewport"
content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width<% if (ctx.mode.cordova || ctx.mode.capacitor) { %>, viewport-fit=cover<% } %>"
/>
<meta charset="utf-8" /> <link rel="icon" type="image/png" sizes="128x128" href="icons/favicon-128x128.png" />
<meta name="description" content="<%= productDescription %>" /> <link rel="icon" type="image/png" sizes="96x96" href="icons/favicon-96x96.png" />
<meta name="format-detection" content="telephone=no" /> <link rel="icon" type="image/png" sizes="32x32" href="icons/favicon-32x32.png" />
<meta name="msapplication-tap-highlight" content="no" /> <link rel="icon" type="image/png" sizes="16x16" href="icons/favicon-16x16.png" />
<meta name="viewport" <link rel="icon" type="image/ico" href="favicon.ico" />
content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width<% if (ctx.mode.cordova || ctx.mode.capacitor) { %>, viewport-fit=cover<% } %>" /> </head>
<link rel="icon" type="image/png" sizes="128x128" href="icons/favicon-128x128.png" /> <body>
<link rel="icon" type="image/png" sizes="96x96" href="icons/favicon-96x96.png" /> <!-- DO NOT touch the following DIV -->
<link rel="icon" type="image/png" sizes="32x32" href="icons/favicon-32x32.png" /> <div id="q-app"></div>
<link rel="icon" type="image/png" sizes="16x16" href="icons/favicon-16x16.png" /> </body>
<link rel="icon" type="image/ico" href="favicon.ico" /> </html>
</head>
<body>
<!-- DO NOT touch the following DIV -->
<div id="q-app"></div>
</body>
</html>

View File

@ -1,6 +1,6 @@
<template> <template>
<q-layout view="hHh lpR fFf"> <q-layout view="hHh lpR fFf">
<Navbar @on-toggle-drawer="onToggleDrawer()" /> <Navbar @toggle-drawer="onToggleDrawer()" />
<q-drawer <q-drawer
v-model="drawer" v-model="drawer"
show-if-above show-if-above
@ -13,23 +13,13 @@
> >
<q-scroll-area class="fit text-grey-8"> <q-scroll-area class="fit text-grey-8">
<q-list padding> <q-list padding>
<q-item <q-item clickable v-ripple :to="{ path: '/dashboard' }" active-class="text-orange">
clickable
v-ripple
:to="{ path: '/dashboard' }"
active-class="text-orange"
>
<q-item-section avatar> <q-item-section avatar>
<q-icon name="dashboard" /> <q-icon name="dashboard" />
</q-item-section> </q-item-section>
<q-item-section>Dashboard</q-item-section> <q-item-section>Dashboard</q-item-section>
</q-item> </q-item>
<q-item <q-item clickable v-ripple :to="{ path: '/customer' }" active-class="text-orange">
clickable
v-ripple
:to="{ path: '/customer' }"
active-class="text-orange"
>
<q-item-section avatar> <q-item-section avatar>
<q-icon name="people" /> <q-icon name="people" />
</q-item-section> </q-item-section>
@ -86,5 +76,4 @@ function onToggleDrawer(): void {
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped></style>
</style>

View File

@ -11,25 +11,14 @@
true-value="en" true-value="en"
v-model="locale" v-model="locale"
/> />
<q-toggle <q-toggle v-model="darkMode" checked-icon="dark_mode" color="orange" unchecked-icon="light_mode" />
v-model="darkMode"
checked-icon="dark_mode"
color="orange"
unchecked-icon="light_mode"
/>
</q-toolbar> </q-toolbar>
</q-header> </q-header>
<q-page-container> <q-page-container>
<q-page> <q-page>
<div id="login"> <div id="login">
<q-card class="login q-pa-xl"> <q-card class="login q-pa-xl">
<q-img <q-img src="~/assets/logo.svg" alt="Logo" fit="contain" :ratio="16 / 9" class="q-mb-md" />
src="~/assets/logo.svg"
alt="Logo"
fit="contain"
:ratio="16 / 9"
class="q-mb-md"
/>
<q-form @submit="onSubmit" class="q-gutter-md"> <q-form @submit="onSubmit" class="q-gutter-md">
<q-input <q-input
filled filled
@ -52,11 +41,7 @@
(val: string) => (val && val.length > 0) || 'Please type something', (val: string) => (val && val.length > 0) || 'Please type something',
]" ]"
/> />
<q-toggle <q-toggle v-model="keepLogin" :label="t('login.keepLogin')" color="orange" />
v-model="keepLogin"
:label="t('login.keepLogin')"
color="orange"
/>
<div> <div>
<q-btn :label="t('login.submit')" type="submit" color="orange" /> <q-btn :label="t('login.submit')" type="submit" color="orange" />

View File

@ -5,15 +5,7 @@
<div class="text-h2" style="opacity: 0.4">Oops. Nothing here...</div> <div class="text-h2" style="opacity: 0.4">Oops. Nothing here...</div>
<q-btn <q-btn class="q-mt-xl" color="white" text-color="blue" unelevated to="/" label="Go Home" no-caps />
class="q-mt-xl"
color="white"
text-color="blue"
unelevated
to="/"
label="Go Home"
no-caps
/>
</div> </div>
</div> </div>
</template> </template>

View File

@ -1,10 +1,5 @@
import { route } from 'quasar/wrappers'; import { route } from 'quasar/wrappers';
import { import { createMemoryHistory, createRouter, createWebHashHistory, createWebHistory } from 'vue-router';
createMemoryHistory,
createRouter,
createWebHashHistory,
createWebHistory,
} from 'vue-router';
import routes from './routes'; import routes from './routes';
import { i18n } from 'src/boot/i18n'; import { i18n } from 'src/boot/i18n';
import { useSession } from 'src/composables/useSession'; import { useSession } from 'src/composables/useSession';
@ -22,8 +17,8 @@ export default route(function (/* { store, ssrContext } */) {
const createHistory = process.env.SERVER const createHistory = process.env.SERVER
? createMemoryHistory ? createMemoryHistory
: process.env.VUE_ROUTER_MODE === 'history' : process.env.VUE_ROUTER_MODE === 'history'
? createWebHistory ? createWebHistory
: createWebHashHistory; : createWebHashHistory;
const Router = createRouter({ const Router = createRouter({
scrollBehavior: () => ({ left: 0, top: 0 }), scrollBehavior: () => ({ left: 0, top: 0 }),
@ -32,13 +27,10 @@ export default route(function (/* { store, ssrContext } */) {
// Leave this as is and make changes in quasar.conf.js instead! // Leave this as is and make changes in quasar.conf.js instead!
// quasar.conf.js -> build -> vueRouterMode // quasar.conf.js -> build -> vueRouterMode
// quasar.conf.js -> build -> publicPath // quasar.conf.js -> build -> publicPath
history: createHistory( history: createHistory(process.env.MODE === 'ssr' ? void 0 : process.env.VUE_ROUTER_BASE),
process.env.MODE === 'ssr' ? void 0 : process.env.VUE_ROUTER_BASE
),
}); });
Router.beforeEach((to, from, next) => { Router.beforeEach((to, from, next) => {
const { isLoggedIn } = session; const { isLoggedIn } = session;
if (!isLoggedIn && to.name !== 'Login') { if (!isLoggedIn && to.name !== 'Login') {
@ -56,7 +48,6 @@ export default route(function (/* { store, ssrContext } */) {
const { t } = i18n.global; const { t } = i18n.global;
let title = ''; let title = '';
const parent = to.matched[1]; const parent = to.matched[1];
if (parent) { if (parent) {
const parentMeta: Meta = parent.meta; const parentMeta: Meta = parent.meta;
@ -76,6 +67,5 @@ export default route(function (/* { store, ssrContext } */) {
document.title = title; document.title = title;
}); });
return Router; return Router;
}); });

View File

@ -1,5 +1,5 @@
{ {
"name": "Using fixtures to represent data", "name": "Using fixtures to represent data",
"email": "hello@cypress.io", "email": "hello@cypress.io",
"body": "Fixtures are a great way to mock data for responses to routes" "body": "Fixtures are a great way to mock data for responses to routes"
} }

View File

@ -6,12 +6,12 @@
// This test will pass when run against a clean Quasar project // This test will pass when run against a clean Quasar project
describe('Landing', () => { describe('Landing', () => {
beforeEach(() => { beforeEach(() => {
cy.visit('/'); cy.visit('/');
}); });
it('.should() - assert that <title> is correct', () => { it('.should() - assert that <title> is correct', () => {
cy.title().should('include', 'Salix'); cy.title().should('include', 'Salix');
}); });
}); });
// ** The following code is an example to show you how to write some tests for your home page ** // ** The following code is an example to show you how to write some tests for your home page **

View File

@ -15,19 +15,17 @@
// cypress/plugins/index.js // cypress/plugins/index.js
const { const { injectDevServer } = require('@quasar/quasar-app-extension-testing-e2e-cypress/cct-dev-server');
injectDevServer,
} = require('@quasar/quasar-app-extension-testing-e2e-cypress/cct-dev-server');
/** /**
* @type {Cypress.PluginConfig} * @type {Cypress.PluginConfig}
*/ */
module.exports = async (on, config) => { module.exports = async (on, config) => {
// Enable component testing, you can safely remove this // Enable component testing, you can safely remove this
// if you don't plan to use Cypress for unit tests // if you don't plan to use Cypress for unit tests
// if (config.testingType === 'component') { // if (config.testingType === 'component') {
// await injectDevServer(on, config); // await injectDevServer(on, config);
// } // }
return config; return config;
}; };

View File

@ -36,7 +36,7 @@ import { Dialog } from 'quasar';
// For example use the actual i18n instance or mock it // For example use the actual i18n instance or mock it
// config.global.plugins.push(i18n); // config.global.plugins.push(i18n);
config.global.mocks = { config.global.mocks = {
$t: () => '', $t: () => '',
}; };
// Overwrite the transition and transition-group stubs which are stubbed by test-utils by default. // Overwrite the transition and transition-group stubs which are stubbed by test-utils by default.

View File

@ -3,24 +3,24 @@ import { defineComponent } from 'vue';
import { Dialog } from 'quasar'; import { Dialog } from 'quasar';
export default defineComponent({ export default defineComponent({
name: 'DialogWrapper', name: 'DialogWrapper',
props: { props: {
component: { component: {
type: Object, type: Object,
required: true, required: true,
},
componentProps: {
type: Object,
default: () => ({}),
},
}, },
componentProps: { setup(props) {
type: Object, Dialog.create({
default: () => ({}), component: props.component,
},
},
setup(props) {
Dialog.create({
component: props.component,
// props forwarded to your custom component // props forwarded to your custom component
componentProps: props.componentProps, componentProps: props.componentProps,
}); });
}, },
}); });
</script> </script>

View File

@ -1,20 +1,20 @@
<template> <template>
<q-layout> <q-layout>
<component :is="component" v-bind="$attrs" /> <component :is="component" v-bind="$attrs" />
</q-layout> </q-layout>
</template> </template>
<script> <script>
import { defineComponent } from 'vue'; import { defineComponent } from 'vue';
export default defineComponent({ export default defineComponent({
name: 'LayoutContainer', name: 'LayoutContainer',
inheritAttrs: false, inheritAttrs: false,
props: { props: {
component: { component: {
type: Object, type: Object,
required: true, required: true,
},
}, },
},
}); });
</script> </script>

View File

@ -19,7 +19,7 @@ describe('MyButton', () => {
const wrapper = mount(MyButton); const wrapper = mount(MyButton);
const { vm } = wrapper; const { vm } = wrapper;
expect((vm.$el).textContent).toContain('rocket muffin'); expect(vm.$el.textContent).toContain('rocket muffin');
expect(wrapper.find('.content').text()).toContain('rocket muffin'); expect(wrapper.find('.content').text()).toContain('rocket muffin');
}); });

View File

@ -12,7 +12,6 @@ const input = ref('rocket muffin');
function increment() { function increment() {
counter.value += props.incrementStep; counter.value += props.incrementStep;
} }
</script> </script>
<template> <template>

View File

@ -1,4 +1,3 @@
<script lang="ts" setup> <script lang="ts" setup>
import { ref } from 'vue'; import { ref } from 'vue';
const isDialogOpen = ref(false); const isDialogOpen = ref(false);

View File

@ -3,4 +3,4 @@
"compilerOptions": { "compilerOptions": {
"baseUrl": "." "baseUrl": "."
} }
} }