forked from verdnatura/salix-front
Merge branch 'dev' into 4834-create-worker-module
This commit is contained in:
commit
7ef50bcbe9
19
.babelrc
19
.babelrc
|
@ -1,19 +0,0 @@
|
|||
{
|
||||
"plugins": ["@babel/plugin-syntax-dynamic-import"],
|
||||
"env": {
|
||||
"test": {
|
||||
"plugins": ["dynamic-import-node"],
|
||||
"presets": [
|
||||
[
|
||||
"@babel/preset-env",
|
||||
{
|
||||
"modules": "commonjs",
|
||||
"targets": {
|
||||
"node": "current"
|
||||
}
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,8 +1,6 @@
|
|||
/dist
|
||||
/src-bex/www
|
||||
/src-capacitor
|
||||
/src-cordova
|
||||
/.quasar
|
||||
/node_modules
|
||||
.eslintrc.js
|
||||
babel.config.js
|
||||
|
|
14
.eslintrc.js
14
.eslintrc.js
|
@ -5,13 +5,13 @@ module.exports = {
|
|||
root: true,
|
||||
|
||||
parserOptions: {
|
||||
parser: '@babel/eslint-parser',
|
||||
ecmaVersion: 2020, // Allows for the parsing of modern ECMAScript features
|
||||
sourceType: 'module', // Allows for the use of imports
|
||||
ecmaVersion: '2021', // Allows for the parsing of modern ECMAScript features
|
||||
},
|
||||
|
||||
env: {
|
||||
node: true,
|
||||
browser: true,
|
||||
'vue/setup-compiler-macros': true,
|
||||
},
|
||||
|
||||
// Rules order is important, please avoid shuffling them
|
||||
|
@ -22,7 +22,7 @@ module.exports = {
|
|||
// Uncomment any of the lines below to choose desired strictness,
|
||||
// but leave only one uncommented!
|
||||
// See https://eslint.vuejs.org/rules/#available-rules
|
||||
//'plugin:vue/vue3-essential', // Priority A: Essential (Error Prevention)
|
||||
// 'plugin:vue/vue3-essential', // Priority A: Essential (Error Prevention)
|
||||
'plugin:vue/vue3-strongly-recommended', // Priority B: Strongly Recommended (Improving Readability)
|
||||
// 'plugin:vue/vue3-recommended', // Priority C: Recommended (Minimizing Arbitrary Choices and Cognitive Overhead)
|
||||
|
||||
|
@ -52,9 +52,6 @@ module.exports = {
|
|||
process: 'readonly',
|
||||
Capacitor: 'readonly',
|
||||
chrome: 'readonly',
|
||||
defineProps: 'readonly', // Vue SFC setup compiler macro
|
||||
defineEmits: 'readonly', // Vue SFC setup compiler macro
|
||||
defineExpose: 'readonly', // Vue SFC setup compiler macro
|
||||
},
|
||||
|
||||
// add your custom rules here
|
||||
|
@ -64,10 +61,9 @@ module.exports = {
|
|||
// allow debugger during development only
|
||||
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
|
||||
},
|
||||
|
||||
overrides: [
|
||||
{
|
||||
files: ['**/*.spec.{js,ts}'],
|
||||
files: ['test/cypress/**/*.spec.{js,ts}'],
|
||||
extends: [
|
||||
// Add Cypress-specific lint rules, globals and Cypress plugin
|
||||
// See https://github.com/cypress-io/eslint-plugin-cypress#rules
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
.DS_Store
|
||||
.thumbs.db
|
||||
node_modules
|
||||
junit.xml
|
||||
|
||||
# Quasar core related directories
|
||||
.quasar
|
||||
|
@ -17,10 +16,6 @@ junit.xml
|
|||
/src-capacitor/www
|
||||
/src-capacitor/node_modules
|
||||
|
||||
# BEX related directories and files
|
||||
/src-bex/www
|
||||
/src-bex/js/core
|
||||
|
||||
# Log files
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
|
@ -32,3 +27,7 @@ yarn-error.log*
|
|||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
|
||||
# Cypress directories and files
|
||||
/tests/cypress/videos
|
||||
/tests/cypress/screenshots
|
|
@ -0,0 +1,3 @@
|
|||
# pnpm-related options
|
||||
shamefully-hoist=true
|
||||
strict-peer-dependencies=false
|
|
@ -1,9 +0,0 @@
|
|||
/* eslint-disable */
|
||||
// https://github.com/michael-ciniawsky/postcss-load-config
|
||||
|
||||
module.exports = {
|
||||
plugins: [
|
||||
// to edit target browsers: use "browserslist" field in package.json
|
||||
require('autoprefixer'),
|
||||
],
|
||||
};
|
|
@ -3,7 +3,7 @@
|
|||
"dbaeumer.vscode-eslint",
|
||||
"esbenp.prettier-vscode",
|
||||
"editorconfig.editorconfig",
|
||||
"Vue.volar",
|
||||
"vue.volar",
|
||||
"wayou.vscode-todo-highlight"
|
||||
],
|
||||
"unwantedRecommendations": [
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [2253.01] - 2023-01-05
|
||||
|
||||
### Added
|
||||
|
||||
- Added...
|
||||
|
||||
### Changed
|
||||
|
||||
- Changed...
|
22
README.md
22
README.md
|
@ -1,12 +1,10 @@
|
|||
# Salix (salix-front)
|
||||
# Lilium (lilium-front)
|
||||
|
||||
Salix front-end
|
||||
Lilium frontend
|
||||
|
||||
## Install the dependencies
|
||||
|
||||
```bash
|
||||
yarn
|
||||
# or
|
||||
npm install
|
||||
```
|
||||
|
||||
|
@ -22,20 +20,16 @@ sudo npm install -g @quasar/cli
|
|||
quasar dev
|
||||
```
|
||||
|
||||
### Lint the files
|
||||
### Run unit tests
|
||||
|
||||
```bash
|
||||
yarn lint
|
||||
# or
|
||||
npm run lint
|
||||
npm run test:unit
|
||||
```
|
||||
|
||||
### Format the files
|
||||
### Run e2e tests
|
||||
|
||||
```bash
|
||||
yarn format
|
||||
# or
|
||||
npm run format
|
||||
npm run test:e2e
|
||||
```
|
||||
|
||||
### Build the app for production
|
||||
|
@ -43,7 +37,3 @@ npm run format
|
|||
```bash
|
||||
quasar build
|
||||
```
|
||||
|
||||
### Customize the configuration
|
||||
|
||||
See [Configuring quasar.config.js](https://v2.quasar.dev/quasar-cli-webpack/quasar-config-js).
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
/* eslint-env node */
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const fs = require('fs-extra');
|
||||
let extend = undefined;
|
||||
|
||||
/**
|
||||
* The .babelrc file has been created to assist Jest for transpiling.
|
||||
* You should keep your application's babel rules in this file.
|
||||
*/
|
||||
|
||||
if (fs.existsSync('./.babelrc')) {
|
||||
extend = './.babelrc';
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
presets: ['@quasar/babel-preset-app'],
|
||||
extends: extend,
|
||||
};
|
|
@ -0,0 +1,22 @@
|
|||
const { defineConfig } = require('cypress');
|
||||
|
||||
module.exports = defineConfig({
|
||||
e2e: {
|
||||
baseUrl: 'http://localhost:8080/',
|
||||
fixturesFolder: 'test/cypress/fixtures',
|
||||
screenshotsFolder: 'test/cypress/screenshots',
|
||||
supportFile: 'test/cypress/support/index.js',
|
||||
videosFolder: 'test/cypress/videos',
|
||||
video: true,
|
||||
specPattern: 'test/cypress/integration/*.spec.js',
|
||||
experimentalRunAllSpecs: true,
|
||||
component: {
|
||||
componentFolder: 'src',
|
||||
testFiles: '**/*.spec.js',
|
||||
supportFile: 'test/cypress/support/unit.js',
|
||||
},
|
||||
setupNodeEvents(on, config) {
|
||||
// implement node event listeners here
|
||||
},
|
||||
},
|
||||
});
|
15
cypress.json
15
cypress.json
|
@ -1,15 +0,0 @@
|
|||
{
|
||||
"baseUrl": "http://localhost:8080/",
|
||||
"fixturesFolder": "tests/cypress/fixtures",
|
||||
"integrationFolder": "tests/cypress/integration",
|
||||
"pluginsFile": "tests/cypress/plugins/index.js",
|
||||
"screenshotsFolder": "tests/cypress/screenshots",
|
||||
"supportFile": "tests/cypress/support/index.js",
|
||||
"videosFolder": "tests/cypress/videos",
|
||||
"video": true,
|
||||
"component": {
|
||||
"componentFolder": "src",
|
||||
"testFiles": "**/*.spec.js",
|
||||
"supportFile": "tests/cypress/support/unit.js"
|
||||
}
|
||||
}
|
|
@ -19,7 +19,6 @@
|
|||
<link rel="icon" type="image/ico" href="favicon.ico" />
|
||||
</head>
|
||||
<body>
|
||||
<!-- DO NOT touch the following DIV -->
|
||||
<div id="q-app"></div>
|
||||
<!-- quasar:entry-point -->
|
||||
</body>
|
||||
</html>
|
|
@ -1,59 +0,0 @@
|
|||
const esModules = ['quasar', 'quasar/lang', 'lodash-es'].join('|');
|
||||
|
||||
module.exports = {
|
||||
globals: {
|
||||
__DEV__: true,
|
||||
// TODO: Remove if resolved natively
|
||||
// See https://github.com/vuejs/vue-jest/issues/175
|
||||
'vue-jest': {
|
||||
pug: { doctype: 'html' },
|
||||
},
|
||||
},
|
||||
// Jest assumes we are testing in node environment, specify jsdom environment instead
|
||||
testEnvironment: 'jsdom',
|
||||
// noStackTrace: true,
|
||||
// bail: true,
|
||||
// cache: false,
|
||||
// verbose: true,
|
||||
// watch: true,
|
||||
reporters: ['default', 'jest-junit'],
|
||||
collectCoverage: false,
|
||||
coverageDirectory: '<rootDir>/tests/jest/coverage',
|
||||
collectCoverageFrom: ['<rootDir>/src/**/*.vue', '<rootDir>/src/**/*.js', '<rootDir>/src/**/*.jsx'],
|
||||
// Needed in JS codebases too because of feature flags
|
||||
coveragePathIgnorePatterns: ['/node_modules/', '.d.ts$'],
|
||||
coverageThreshold: {
|
||||
global: {
|
||||
// branches: 50,
|
||||
// functions: 50,
|
||||
// lines: 50,
|
||||
// statements: 50
|
||||
},
|
||||
},
|
||||
testMatch: ['<rootDir>/src/**/__tests__/*.(spec|test).+(ts|js)?(x)'],
|
||||
moduleFileExtensions: ['vue', 'js', 'jsx', 'json'],
|
||||
moduleNameMapper: {
|
||||
'^quasar$': 'quasar/dist/quasar.esm.prod.js',
|
||||
'^~/(.*)$': '<rootDir>/$1',
|
||||
'^src/(.*)$': '<rootDir>/src/$1',
|
||||
'^app/(.*)$': '<rootDir>/$1',
|
||||
'^components/(.*)$': '<rootDir>/src/components/$1',
|
||||
'^composables/(.*)$': '<rootDir>/src/composables/$1',
|
||||
'^filters/(.*)$': '<rootDir>/src/filters/$1',
|
||||
'^layouts/(.*)$': '<rootDir>/src/layouts/$1',
|
||||
'^pages/(.*)$': '<rootDir>/src/pages/$1',
|
||||
'^assets/(.*)$': '<rootDir>/src/assets/$1',
|
||||
'^boot/(.*)$': '<rootDir>/src/boot/$1',
|
||||
'.*css$': '@quasar/quasar-app-extension-testing-unit-jest/stub.css',
|
||||
},
|
||||
transform: {
|
||||
'.*\\.vue$': 'vue-jest',
|
||||
'.*\\.js$': 'babel-jest',
|
||||
'.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$': 'jest-transform-stub',
|
||||
// use these if NPM is being flaky, care as hosting could interfere with these
|
||||
// '.*\\.vue$': '@quasar/quasar-app-extension-testing-unit-jest/node_modules/vue-jest',
|
||||
// '.*\\.js$': '@quasar/quasar-app-extension-testing-unit-jest/node_modules/babel-jest'
|
||||
},
|
||||
transformIgnorePatterns: [`node_modules/(?!(${esModules}))`],
|
||||
snapshotSerializers: ['jest-serializer-vue'],
|
||||
};
|
|
@ -14,8 +14,5 @@
|
|||
"vue$": ["node_modules/vue/dist/vue.runtime.esm-bundler.js"]
|
||||
}
|
||||
},
|
||||
"exclude": ["dist", ".quasar", "node_modules"],
|
||||
"vueCompilerOptions": {
|
||||
"experimentalDisableTemplateSupport": true
|
||||
}
|
||||
"exclude": ["dist", ".quasar", "node_modules"]
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
55
package.json
55
package.json
|
@ -1,63 +1,54 @@
|
|||
{
|
||||
"name": "salix-front",
|
||||
"version": "0.0.1",
|
||||
"description": "Salix front-end",
|
||||
"description": "Salix frontend",
|
||||
"productName": "Salix",
|
||||
"author": "Verdnatura",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"lint": "eslint --ext .js,.vue ./",
|
||||
"format": "prettier --write \"**/*.{js,vue,scss,html,md,json}\" --ignore-path .gitignore",
|
||||
"test:e2e": "cypress open",
|
||||
"test:e2e:ci": "cypress run --browser chromium",
|
||||
"test": "echo \"See package.json => scripts for available tests.\" && exit 0",
|
||||
"test:unit": "jest --reporters=default --watchAll",
|
||||
"test:unit:ci": "jest --ci --reporters=default --reporters=jest-junit --maxWorkers=2",
|
||||
"test:unit:coverage": "jest --coverage",
|
||||
"serve:test:coverage": "quasar serve test/jest/coverage/lcov-report/ --port 8788",
|
||||
"concurrently:dev:jest": "concurrently \"quasar dev\" \"jest --watch\"",
|
||||
"test:e2e": "cross-env E2E_TEST=true start-test \"quasar dev\" http-get://localhost:8080 \"cypress open\"",
|
||||
"test:e2e:ci": "cross-env E2E_TEST=true start-test \"quasar dev\" http-get://localhost:8080 \"cypress run\""
|
||||
"test:unit": "vitest",
|
||||
"test:unit:ci": "vitest run"
|
||||
},
|
||||
"dependencies": {
|
||||
"@quasar/extras": "^1.15.8",
|
||||
"axios": "^1.2.1",
|
||||
"core-js": "^3.6.5",
|
||||
"pinia": "^2.0.28",
|
||||
"quasar": "^2.11.1",
|
||||
"validator": "^13.7.0",
|
||||
"vue": "^3.2.45",
|
||||
"vue-i18n": "^9.2.2",
|
||||
"vue-router": "^4.1.6"
|
||||
"vue-router": "^4.1.6",
|
||||
"vue-router-mock": "^0.1.9"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/eslint-parser": "^7.13.14",
|
||||
"@intlify/vue-i18n-loader": "^4.1.0",
|
||||
"@intlify/unplugin-vue-i18n": "^0.8.1",
|
||||
"@pinia/testing": "^0.0.14",
|
||||
"@quasar/app-webpack": "^3.6.2",
|
||||
"@quasar/quasar-app-extension-testing-e2e-cypress": "^4.2.2",
|
||||
"@quasar/quasar-app-extension-testing-unit-jest": "^3.0.0-beta.5",
|
||||
"@quasar/app-vite": "^1.1.3",
|
||||
"@quasar/quasar-app-extension-testing-unit-vitest": "^0.1.2",
|
||||
"@vue/test-utils": "^2.0.0",
|
||||
"autoprefixer": "^10.4.13",
|
||||
"cypress": "^12.2.0",
|
||||
"eslint": "^8.30.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-cypress": "^2.12.1",
|
||||
"eslint-plugin-jest": "^27.1.7",
|
||||
"eslint-plugin-vue": "^8.7.1",
|
||||
"eslint-webpack-plugin": "^3.2.0",
|
||||
"jest-junit": "^13.0.0",
|
||||
"prettier": "^2.5.1"
|
||||
"eslint-plugin-vue": "^9.8.0",
|
||||
"postcss": "^8.4.20",
|
||||
"prettier": "^2.8.1",
|
||||
"vitest": "^0.26.3"
|
||||
},
|
||||
"browserslist": [
|
||||
"last 10 Chrome versions",
|
||||
"last 10 Firefox versions",
|
||||
"last 4 Edge versions",
|
||||
"last 7 Safari versions",
|
||||
"last 8 Android versions",
|
||||
"last 8 ChromeAndroid versions",
|
||||
"last 8 FirefoxAndroid versions",
|
||||
"last 10 iOS versions",
|
||||
"last 5 Opera versions"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 12.22.1",
|
||||
"node": "^18 || ^16 || ^14.19",
|
||||
"npm": ">= 6.13.4",
|
||||
"yarn": ">= 1.21.1"
|
||||
},
|
||||
"overrides": {
|
||||
"@vitejs/plugin-vue": "^4.0.0",
|
||||
"vite": "^4.0.3",
|
||||
"vitest": "^0.26.3"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
/* eslint-disable */
|
||||
// https://github.com/michael-ciniawsky/postcss-load-config
|
||||
|
||||
module.exports = {
|
||||
plugins: [
|
||||
// https://github.com/postcss/autoprefixer
|
||||
require('autoprefixer')({
|
||||
overrideBrowserslist: [
|
||||
'last 4 Chrome versions',
|
||||
'last 4 Firefox versions',
|
||||
'last 4 Edge versions',
|
||||
'last 4 Safari versions',
|
||||
'last 4 Android versions',
|
||||
'last 4 ChromeAndroid versions',
|
||||
'last 4 FirefoxAndroid versions',
|
||||
'last 4 iOS versions',
|
||||
],
|
||||
}),
|
||||
|
||||
// https://github.com/elchininet/postcss-rtlcss
|
||||
// If you want to support RTL css, then
|
||||
// 1. yarn/npm install postcss-rtlcss
|
||||
// 2. optionally set quasar.config.js > framework > lang to an RTL language
|
||||
// 3. uncomment the following line:
|
||||
// require('postcss-rtlcss')
|
||||
],
|
||||
};
|
238
quasar.config.js
238
quasar.config.js
|
@ -6,26 +6,32 @@
|
|||
*/
|
||||
|
||||
// Configuration for your app
|
||||
// https://v2.quasar.dev/quasar-cli-webpack/quasar-config-js
|
||||
// https://v2.quasar.dev/quasar-cli-vite/quasar-config-js
|
||||
|
||||
const ESLintPlugin = require('eslint-webpack-plugin');
|
||||
const { configure } = require('quasar/wrappers');
|
||||
const VueI18nPlugin = require('@intlify/unplugin-vue-i18n/vite')
|
||||
const path = require('path');
|
||||
|
||||
module.exports = configure(function (ctx) {
|
||||
module.exports = configure(function (/* ctx */) {
|
||||
return {
|
||||
// https://v2.quasar.dev/quasar-cli-webpack/supporting-ts
|
||||
supportTS: false,
|
||||
eslint: {
|
||||
// fix: true,
|
||||
// include = [],
|
||||
// exclude = [],
|
||||
// rawOptions = {},
|
||||
warnings: true,
|
||||
errors: true,
|
||||
},
|
||||
|
||||
// https://v2.quasar.dev/quasar-cli-webpack/prefetch-feature
|
||||
// https://v2.quasar.dev/quasar-cli/prefetch-feature
|
||||
// preFetch: true,
|
||||
|
||||
// app boot file (/src/boot)
|
||||
// --> boot files are part of "main.js"
|
||||
// https://v2.quasar.dev/quasar-cli-webpack/boot-files
|
||||
boot: ['i18n', 'axios', 'pinia'],
|
||||
// https://v2.quasar.dev/quasar-cli/boot-files
|
||||
boot: ['i18n', 'axios'],
|
||||
|
||||
// https://v2.quasar.dev/quasar-cli-webpack/quasar-config-js#Property%3A-css
|
||||
// https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#css
|
||||
css: ['app.scss'],
|
||||
|
||||
// https://github.com/quasarframework/quasar/tree/dev/extras
|
||||
|
@ -43,58 +49,63 @@ module.exports = configure(function (ctx) {
|
|||
'material-symbols-outlined',
|
||||
],
|
||||
|
||||
// Full list of options: https://v2.quasar.dev/quasar-cli-webpack/quasar-config-js#Property%3A-build
|
||||
// Full list of options: https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#build
|
||||
build: {
|
||||
vueRouterMode: 'hash', // available values: 'hash', 'history'
|
||||
|
||||
// transpile: false,
|
||||
// publicPath: '/',
|
||||
|
||||
// Add dependencies for transpiling with Babel (Array of string/regex)
|
||||
// (from node_modules, which are by default not transpiled).
|
||||
// Applies only if "transpile" is set to true.
|
||||
// transpileDependencies: [],
|
||||
|
||||
// rtl: true, // https://quasar.dev/options/rtl-support
|
||||
// preloadChunks: true,
|
||||
// showProgress: false,
|
||||
// gzip: true,
|
||||
// analyze: true,
|
||||
|
||||
// Options below are automatically set depending on the env, set them if you want to override
|
||||
// extractCSS: false,
|
||||
|
||||
// https://v2.quasar.dev/quasar-cli-webpack/handling-webpack
|
||||
// "chain" is a webpack-chain object https://github.com/neutrinojs/webpack-chain
|
||||
|
||||
chainWebpack(chain) {
|
||||
chain.module
|
||||
.rule('i18n')
|
||||
.resourceQuery(/blockType=i18n/)
|
||||
.type('javascript/auto')
|
||||
.use('i18n')
|
||||
.loader('@intlify/vue-i18n-loader')
|
||||
.end();
|
||||
|
||||
chain.plugin('eslint-webpack-plugin').use(ESLintPlugin, [{ extensions: ['js', 'vue'] }]);
|
||||
target: {
|
||||
browser: ['es2022', 'edge88', 'firefox78', 'chrome87', 'safari13.1'],
|
||||
node: 'node18',
|
||||
},
|
||||
extendWebpack(cfg) {
|
||||
cfg.resolve.alias = {
|
||||
...cfg.resolve.alias, // This adds the existing alias
|
||||
|
||||
// Add your own alias like this
|
||||
composables: path.resolve(__dirname, './src/composables'),
|
||||
filters: path.resolve(__dirname, './src/filters'),
|
||||
vueRouterMode: 'hash', // available values: 'hash', 'history'
|
||||
// vueRouterBase,
|
||||
// vueDevtools,
|
||||
// vueOptionsAPI: false,
|
||||
|
||||
// rebuildCache: true, // rebuilds Vite/linter/etc cache on startup
|
||||
|
||||
// publicPath: '/',
|
||||
// analyze: true,
|
||||
// env: {},
|
||||
// rawDefine: {}
|
||||
// ignorePublicFolder: true,
|
||||
// minify: false,
|
||||
// polyfillModulePreload: true,
|
||||
// distDir
|
||||
|
||||
extendViteConf(viteConf) {
|
||||
// FIXME: Delete deprecated property polyfillModulePreload
|
||||
// that is set by Quasar by default
|
||||
delete viteConf.build.polyfillModulePreload;
|
||||
viteConf.build.modulePreload = {
|
||||
polyfill: false,
|
||||
};
|
||||
},
|
||||
// viteVuePluginOptions: {},
|
||||
|
||||
alias: {
|
||||
composables: path.join(__dirname, './src/composables'),
|
||||
filters: path.join(__dirname, './src/filters'),
|
||||
},
|
||||
|
||||
vitePlugins: [
|
||||
[
|
||||
VueI18nPlugin,
|
||||
{
|
||||
// if you want to use Vue I18n Legacy API, you need to set `compositionOnly: false`
|
||||
// compositionOnly: false,
|
||||
|
||||
// you need to set i18n resource including paths !
|
||||
include: path.resolve(__dirname, './src/i18n/**'),
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
|
||||
// Full list of options: https://v2.quasar.dev/quasar-cli-webpack/quasar-config-js#Property%3A-devServer
|
||||
// Full list of options: https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#devServer
|
||||
devServer: {
|
||||
server: {
|
||||
type: 'http',
|
||||
},
|
||||
port: 8080,
|
||||
proxy: {
|
||||
'/api': {
|
||||
target: 'http://0.0.0.0:3000',
|
||||
|
@ -105,15 +116,17 @@ module.exports = configure(function (ctx) {
|
|||
},
|
||||
},
|
||||
|
||||
// https://v2.quasar.dev/quasar-cli-webpack/quasar-config-js#Property%3A-framework
|
||||
// https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#framework
|
||||
framework: {
|
||||
config: {
|
||||
brand: {
|
||||
primary: 'orange',
|
||||
config: {
|
||||
brand: {
|
||||
primary: 'orange',
|
||||
},
|
||||
dark: 'auto',
|
||||
},
|
||||
dark: 'auto',
|
||||
},
|
||||
lang: 'es',
|
||||
lang: 'en-GB',
|
||||
|
||||
// iconSet: 'material-icons', // Quasar icon set
|
||||
// lang: 'en-US', // Quasar language pack
|
||||
|
@ -130,11 +143,29 @@ module.exports = configure(function (ctx) {
|
|||
},
|
||||
|
||||
// animations: 'all', // --- includes all animations
|
||||
// https://quasar.dev/options/animations
|
||||
// https://v2.quasar.dev/options/animations
|
||||
animations: [],
|
||||
|
||||
// https://v2.quasar.dev/quasar-cli-webpack/developing-ssr/configuring-ssr
|
||||
// https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#property-sourcefiles
|
||||
// sourceFiles: {
|
||||
// rootComponent: 'src/App.vue',
|
||||
// router: 'src/router/index',
|
||||
// store: 'src/store/index',
|
||||
// registerServiceWorker: 'src-pwa/register-service-worker',
|
||||
// serviceWorker: 'src-pwa/custom-service-worker',
|
||||
// pwaManifestFile: 'src-pwa/manifest.json',
|
||||
// electronMain: 'src-electron/electron-main',
|
||||
// electronPreload: 'src-electron/electron-preload'
|
||||
// },
|
||||
|
||||
// https://v2.quasar.dev/quasar-cli/developing-ssr/configuring-ssr
|
||||
ssr: {
|
||||
// ssrPwaHtmlFilename: 'offline.html', // do NOT use index.html as name!
|
||||
// will mess up SSR
|
||||
|
||||
// extendSSRWebserverConf (esbuildConf) {},
|
||||
// extendPackageJson (json) {},
|
||||
|
||||
pwa: false,
|
||||
|
||||
// manualStoreHydration: true,
|
||||
|
@ -143,81 +174,42 @@ module.exports = configure(function (ctx) {
|
|||
prodPort: 3000, // The default port that the production server should use
|
||||
// (gets superseded if process.env.PORT is specified at runtime)
|
||||
|
||||
maxAge: 1000 * 60 * 60 * 24 * 30,
|
||||
// Tell browser when a file from the server should expire from cache (in ms)
|
||||
|
||||
chainWebpackWebserver(chain) {
|
||||
chain.plugin('eslint-webpack-plugin').use(ESLintPlugin, [{ extensions: ['js'] }]);
|
||||
},
|
||||
|
||||
middlewares: [
|
||||
ctx.prod ? 'compression' : '',
|
||||
'render', // keep this as last one
|
||||
],
|
||||
},
|
||||
|
||||
// https://v2.quasar.dev/quasar-cli-webpack/developing-pwa/configuring-pwa
|
||||
// https://v2.quasar.dev/quasar-cli/developing-pwa/configuring-pwa
|
||||
pwa: {
|
||||
workboxPluginMode: 'GenerateSW', // 'GenerateSW' or 'InjectManifest'
|
||||
workboxOptions: {}, // only for GenerateSW
|
||||
|
||||
// for the custom service worker ONLY (/src-pwa/custom-service-worker.[js|ts])
|
||||
// if using workbox in InjectManifest mode
|
||||
|
||||
chainWebpackCustomSW(chain) {
|
||||
chain.plugin('eslint-webpack-plugin').use(ESLintPlugin, [{ extensions: ['js'] }]);
|
||||
},
|
||||
|
||||
manifest: {
|
||||
name: `Salix`,
|
||||
short_name: `Salix`,
|
||||
description: `Salix front-end`,
|
||||
display: 'standalone',
|
||||
orientation: 'portrait',
|
||||
background_color: '#ffffff',
|
||||
theme_color: '#027be3',
|
||||
icons: [
|
||||
{
|
||||
src: 'icons/icon-128x128.png',
|
||||
sizes: '128x128',
|
||||
type: 'image/png',
|
||||
},
|
||||
{
|
||||
src: 'icons/icon-192x192.png',
|
||||
sizes: '192x192',
|
||||
type: 'image/png',
|
||||
},
|
||||
{
|
||||
src: 'icons/icon-256x256.png',
|
||||
sizes: '256x256',
|
||||
type: 'image/png',
|
||||
},
|
||||
{
|
||||
src: 'icons/icon-384x384.png',
|
||||
sizes: '384x384',
|
||||
type: 'image/png',
|
||||
},
|
||||
{
|
||||
src: 'icons/icon-512x512.png',
|
||||
sizes: '512x512',
|
||||
type: 'image/png',
|
||||
},
|
||||
],
|
||||
},
|
||||
workboxMode: 'generateSW', // or 'injectManifest'
|
||||
injectPwaMetaTags: true,
|
||||
swFilename: 'sw.js',
|
||||
manifestFilename: 'manifest.json',
|
||||
useCredentialsForManifestTag: false,
|
||||
// useFilenameHashes: true,
|
||||
// extendGenerateSWOptions (cfg) {}
|
||||
// extendInjectManifestOptions (cfg) {},
|
||||
// extendManifestJson (json) {}
|
||||
// extendPWACustomSWConf (esbuildConf) {}
|
||||
},
|
||||
|
||||
// Full list of options: https://v2.quasar.dev/quasar-cli-webpack/developing-cordova-apps/configuring-cordova
|
||||
// Full list of options: https://v2.quasar.dev/quasar-cli/developing-cordova-apps/configuring-cordova
|
||||
cordova: {
|
||||
// noIosLegacyBuildFlag: true, // uncomment only if you know what you are doing
|
||||
},
|
||||
|
||||
// Full list of options: https://v2.quasar.dev/quasar-cli-webpack/developing-capacitor-apps/configuring-capacitor
|
||||
// Full list of options: https://v2.quasar.dev/quasar-cli/developing-capacitor-apps/configuring-capacitor
|
||||
capacitor: {
|
||||
hideSplashscreen: true,
|
||||
},
|
||||
|
||||
// Full list of options: https://v2.quasar.dev/quasar-cli-webpack/developing-electron-apps/configuring-electron
|
||||
// Full list of options: https://v2.quasar.dev/quasar-cli/developing-electron-apps/configuring-electron
|
||||
electron: {
|
||||
// extendElectronMainConf (esbuildConf)
|
||||
// extendElectronPreloadConf (esbuildConf)
|
||||
|
||||
inspectPort: 5858,
|
||||
|
||||
bundler: 'packager', // 'packager' or 'builder'
|
||||
|
||||
packager: {
|
||||
|
@ -234,18 +226,16 @@ module.exports = configure(function (ctx) {
|
|||
builder: {
|
||||
// https://www.electron.build/configuration/configuration
|
||||
|
||||
appId: 'salix-front',
|
||||
appId: 'salix-frontend',
|
||||
},
|
||||
},
|
||||
|
||||
// "chain" is a webpack-chain object https://github.com/neutrinojs/webpack-chain
|
||||
// Full list of options: https://v2.quasar.dev/quasar-cli-vite/developing-browser-extensions/configuring-bex
|
||||
bex: {
|
||||
contentScripts: ['my-content-script'],
|
||||
|
||||
chainWebpackMain(chain) {
|
||||
chain.plugin('eslint-webpack-plugin').use(ESLintPlugin, [{ extensions: ['js'] }]);
|
||||
},
|
||||
|
||||
chainWebpackPreload(chain) {
|
||||
chain.plugin('eslint-webpack-plugin').use(ESLintPlugin, [{ extensions: ['js'] }]);
|
||||
},
|
||||
// extendBexScriptsConf (esbuildConf) {}
|
||||
// extendBexManifestJson (json) {}
|
||||
},
|
||||
};
|
||||
});
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
{
|
||||
"@quasar/testing-unit-jest": {
|
||||
"babel": "babelrc",
|
||||
"options": ["scripts"]
|
||||
},
|
||||
"@quasar/testing-e2e-cypress": {
|
||||
"options": ["scripts"]
|
||||
}
|
||||
}
|
||||
"@quasar/testing-unit-vitest": {
|
||||
"options": [
|
||||
"scripts"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -1,11 +1,5 @@
|
|||
{
|
||||
"unit-jest": {
|
||||
"runnerCommand": "jest --ci"
|
||||
},
|
||||
"e2e-cypress": {
|
||||
"runnerCommand": "cross-env E2E_TEST=true start-test \"quasar dev\" http-get://localhost:8080 \"cypress run\""
|
||||
},
|
||||
"unit-cypress": {
|
||||
"runnerCommand": "cypress run-ct"
|
||||
}
|
||||
}
|
||||
"unit-vitest": {
|
||||
"runnerCommand": "vitest run"
|
||||
}
|
||||
}
|
|
@ -1,21 +1,24 @@
|
|||
import { boot } from 'quasar/wrappers';
|
||||
import axios from 'axios';
|
||||
import { useSession } from 'src/composables/useSession';
|
||||
|
||||
const { getToken } = useSession();
|
||||
export default boot(() => {
|
||||
const { getToken } = useSession();
|
||||
|
||||
axios.defaults.baseURL = '/api/';
|
||||
axios.defaults.baseURL = '/api/';
|
||||
|
||||
axios.interceptors.request.use(
|
||||
function (context) {
|
||||
const token = getToken();
|
||||
axios.interceptors.request.use(
|
||||
function (context) {
|
||||
const token = getToken();
|
||||
|
||||
if (token.length && context.headers) {
|
||||
context.headers.Authorization = token;
|
||||
if (token.length && context.headers) {
|
||||
context.headers.Authorization = token;
|
||||
}
|
||||
|
||||
return context;
|
||||
},
|
||||
function (error) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
|
||||
return context;
|
||||
},
|
||||
function (error) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
);
|
||||
});
|
||||
|
|
|
@ -5,9 +5,10 @@ import messages from 'src/i18n';
|
|||
const i18n = createI18n({
|
||||
locale: 'en',
|
||||
fallbackLocale: 'en',
|
||||
globalInjection: true,
|
||||
messages,
|
||||
missingWarn: false,
|
||||
legacy: false,
|
||||
missingWarn: false
|
||||
});
|
||||
|
||||
export default boot(({ app }) => {
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
import { boot } from 'quasar/wrappers';
|
||||
import { createPinia } from 'pinia';
|
||||
|
||||
export default boot(({ app }) => {
|
||||
const pinia = createPinia();
|
||||
|
||||
app.use(pinia);
|
||||
});
|
|
@ -14,30 +14,31 @@ const pinnedModules = computed(() => navigation.getPinnedModules());
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<q-menu
|
||||
anchor="bottom left"
|
||||
class="row q-pa-md q-col-gutter-lg"
|
||||
max-width="350px"
|
||||
max-height="400px"
|
||||
v-if="pinnedModules.length"
|
||||
>
|
||||
<div v-for="item of pinnedModules" :key="item.title" class="row no-wrap q-pa-xs flex-item">
|
||||
<q-btn
|
||||
align="evenly"
|
||||
padding="16px"
|
||||
flat
|
||||
stack
|
||||
size="lg"
|
||||
:icon="item.icon"
|
||||
color="primary"
|
||||
class="col-4 button"
|
||||
:to="{ name: item.name }"
|
||||
>
|
||||
<div class="text-center text-primary button-text">
|
||||
{{ t(item.title) }}
|
||||
</div>
|
||||
</q-btn>
|
||||
</div>
|
||||
<q-menu anchor="bottom left" class="row q-pa-md q-col-gutter-lg" max-width="350px" max-height="400px">
|
||||
<template v-if="pinnedModules.length">
|
||||
<div v-for="item of pinnedModules" :key="item.title" class="row no-wrap q-pa-xs flex-item">
|
||||
<q-btn
|
||||
align="evenly"
|
||||
padding="16px"
|
||||
flat
|
||||
stack
|
||||
size="lg"
|
||||
:icon="item.icon"
|
||||
color="primary"
|
||||
class="col-4 button"
|
||||
:to="{ name: item.name }"
|
||||
>
|
||||
<div class="text-center text-primary button-text">
|
||||
{{ t(item.title) }}
|
||||
</div>
|
||||
</q-btn>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="row no-wrap q-pa-xs flex-item text-center text-grey-5" style="min-width: 200px">
|
||||
{{ t('globals.noPinnedModules') }}
|
||||
</div>
|
||||
</template>
|
||||
</q-menu>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -22,9 +22,16 @@ const userLocale = computed({
|
|||
|
||||
if (value === 'en') value = 'en-GB';
|
||||
|
||||
import(`quasar/lang/${value}`).then((language) => {
|
||||
Quasar.lang.set(language.default);
|
||||
});
|
||||
// FIXME: Dynamic imports from absolute paths are not compatible with vite:
|
||||
// https://github.com/rollup/plugins/tree/master/packages/dynamic-import-vars#limitations
|
||||
try {
|
||||
const langList = import.meta.glob('../../node_modules/quasar/lang/*.mjs');
|
||||
langList[`../../node_modules/quasar/lang/${value}.mjs`]().then((lang) => {
|
||||
Quasar.lang.set(lang.default);
|
||||
});
|
||||
} catch (error) {
|
||||
//
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
|
|
|
@ -1,104 +0,0 @@
|
|||
import { jest, describe, expect, it, beforeAll } from '@jest/globals';
|
||||
import { createWrapper } from 'app/tests/jest/jestHelpers';
|
||||
import Leftmenu from '../LeftMenu.vue';
|
||||
|
||||
import { createTestingPinia } from '@pinia/testing';
|
||||
import { useNavigationStore } from 'src/stores/useNavigationStore';
|
||||
|
||||
const mockPush = jest.fn();
|
||||
|
||||
jest.mock('vue-router', () => ({
|
||||
useRouter: () => ({
|
||||
push: mockPush,
|
||||
currentRoute: { value: 'myCurrentRoute' },
|
||||
}),
|
||||
useRoute: () => ({
|
||||
matched: [],
|
||||
}),
|
||||
}));
|
||||
|
||||
jest.mock('src/router/modules', () => [
|
||||
{
|
||||
path: '/customer',
|
||||
name: 'Customer',
|
||||
meta: {
|
||||
title: 'customers',
|
||||
icon: 'vn:client',
|
||||
},
|
||||
menus: {
|
||||
main: ['CustomerList', 'CustomerCreate'],
|
||||
card: ['CustomerBasicData'],
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
name: 'CustomerMain',
|
||||
children: [
|
||||
{
|
||||
path: 'list',
|
||||
name: 'CustomerList',
|
||||
meta: {
|
||||
title: 'list',
|
||||
icon: 'view_list',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'create',
|
||||
name: 'CustomerCreate',
|
||||
meta: {
|
||||
title: 'createCustomer',
|
||||
icon: 'vn:addperson',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
|
||||
describe('Leftmenu', () => {
|
||||
let vm;
|
||||
let navigation;
|
||||
beforeAll(async () => {
|
||||
vm = createWrapper(Leftmenu, {
|
||||
propsData: {
|
||||
source: 'main',
|
||||
},
|
||||
global: {
|
||||
plugins: [createTestingPinia({ stubActions: false })],
|
||||
},
|
||||
}).vm;
|
||||
|
||||
navigation = useNavigationStore();
|
||||
navigation.modules = ['customer']; // I should mock to have just one module but isn´t working
|
||||
navigation.fetchPinned = jest.fn().mockReturnValue(Promise.resolve(true));
|
||||
navigation.getModules = jest.fn().mockReturnValue({
|
||||
value: [
|
||||
{
|
||||
name: 'customer',
|
||||
title: 'customer.pageTitles.customers',
|
||||
icon: 'vn:customer',
|
||||
module: 'customer',
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it('should return a proper formated object with two child items', async () => {
|
||||
const expectedMenuItem = [
|
||||
{
|
||||
name: 'CustomerList',
|
||||
title: 'customer.pageTitles.list',
|
||||
icon: 'view_list',
|
||||
},
|
||||
{
|
||||
name: 'CustomerCreate',
|
||||
title: 'customer.pageTitles.createCustomer',
|
||||
icon: 'vn:addperson',
|
||||
},
|
||||
];
|
||||
|
||||
const firstMenuItem = vm.items[0];
|
||||
expect(firstMenuItem.children).toEqual(expect.arrayContaining(expectedMenuItem));
|
||||
});
|
||||
});
|
|
@ -0,0 +1,49 @@
|
|||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { useDialogPluginComponent } from 'quasar';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const $props = defineProps({
|
||||
question: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
message: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
});
|
||||
|
||||
defineEmits(['confirm', ...useDialogPluginComponent.emits]);
|
||||
|
||||
const { dialogRef, onDialogOK } = useDialogPluginComponent();
|
||||
const { t } = useI18n();
|
||||
|
||||
const question = ref($props.question);
|
||||
const message = ref($props.question);
|
||||
const isLoading = ref(false);
|
||||
</script>
|
||||
<template>
|
||||
<q-dialog ref="dialogRef" persistent>
|
||||
<q-card class="q-pa-sm">
|
||||
<q-card-section class="row items-center q-pb-none">
|
||||
<span class="text-h6 text-grey">{{ message }}</span>
|
||||
<q-space />
|
||||
<q-btn icon="close" flat round dense v-close-popup />
|
||||
</q-card-section>
|
||||
<q-card-section class="row items-center">
|
||||
{{ question }}
|
||||
</q-card-section>
|
||||
<q-card-actions align="right">
|
||||
<q-btn :label="t('globals.cancel')" color="primary" flat v-close-popup />
|
||||
<q-btn :label="t('globals.confirm')" color="primary" :loading="isLoading" @click="onDialogOK" />
|
||||
</q-card-actions>
|
||||
</q-card>
|
||||
</q-dialog>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.q-card {
|
||||
min-width: 350px;
|
||||
}
|
||||
</style>
|
|
@ -1,112 +0,0 @@
|
|||
import * as validator from 'validator';
|
||||
|
||||
export const validators = {
|
||||
presence: ($translate, value) => {
|
||||
if (validator.isEmpty(value ? String(value) : ''))
|
||||
throw new Error(_($translate, `Value can't be empty`));
|
||||
},
|
||||
absence: ($translate, value) => {
|
||||
if (!validator.isEmpty(value))
|
||||
throw new Error(_($translate, `Value should be empty`));
|
||||
},
|
||||
length: ($translate, value, conf) => {
|
||||
let options = {
|
||||
min: conf.min || conf.is,
|
||||
max: conf.max || conf.is
|
||||
};
|
||||
let val = value ? String(value) : '';
|
||||
if (!validator.isLength(val, options)) {
|
||||
if (conf.is) {
|
||||
throw new Error(_($translate,
|
||||
`Value should be %s characters long`, [conf.is]));
|
||||
} else if (conf.min && conf.max) {
|
||||
throw new Error(_($translate,
|
||||
`Value should have a length between %s and %s`, [conf.min, conf.max]));
|
||||
} else if (conf.min) {
|
||||
throw new Error(_($translate,
|
||||
`Value should have at least %s characters`, [conf.min]));
|
||||
} else {
|
||||
throw new Error(_($translate,
|
||||
`Value should have at most %s characters`, [conf.max]));
|
||||
}
|
||||
}
|
||||
},
|
||||
numericality: ($translate, value, conf) => {
|
||||
if (conf.int) {
|
||||
if (!validator.isInt(value))
|
||||
throw new Error(_($translate, `Value should be integer`));
|
||||
} else if (!validator.isNumeric(value))
|
||||
throw new Error(_($translate, `Value should be a number`));
|
||||
},
|
||||
inclusion: ($translate, value, conf) => {
|
||||
if (!validator.isIn(value, conf.in))
|
||||
throw new Error(_($translate, `Invalid value`));
|
||||
},
|
||||
exclusion: ($translate, value, conf) => {
|
||||
if (validator.isIn(value, conf.in))
|
||||
throw new Error(_($translate, `Invalid value`));
|
||||
},
|
||||
format: ($translate, value, conf) => {
|
||||
if (!validator.matches(value, conf.with))
|
||||
throw new Error(_($translate, `Invalid value`));
|
||||
},
|
||||
custom: ($translate, value, conf) => {
|
||||
if (!conf.bindedFunction(value))
|
||||
throw new Error(_($translate, `Invalid value`));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks if value satisfies a set of validations.
|
||||
*
|
||||
* @param {*} value The value
|
||||
* @param {Array} validations Array with validations
|
||||
*/
|
||||
export function validateAll($translate, value, validations) {
|
||||
for (let conf of validations)
|
||||
validate($translate, value, conf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if value satisfies a validation.
|
||||
*
|
||||
* @param {*} value The value
|
||||
* @param {Object} conf The validation configuration
|
||||
*/
|
||||
export function validate($translate, value, conf) {
|
||||
let validator = validators[conf.validation];
|
||||
try {
|
||||
let isEmpty = value == null || value === '';
|
||||
|
||||
if (isEmpty)
|
||||
checkNull($translate, value, conf);
|
||||
if (validator && (!isEmpty || conf.validation == 'presence'))
|
||||
validator($translate, value, conf);
|
||||
} catch (e) {
|
||||
let message = conf.message ? conf.message : e.message;
|
||||
throw new Error(_($translate, message));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if value satisfies a blank or not null validation.
|
||||
*
|
||||
* @param {*} value The value
|
||||
* @param {Object} conf The validation configuration
|
||||
*/
|
||||
export function checkNull($translate, value, conf) {
|
||||
if (conf.allowBlank === false && value === '')
|
||||
throw new Error(_($translate, `Value can't be blank`));
|
||||
else if (conf.allowNull === false && value == null)
|
||||
throw new Error(_($translate, `Value can't be null`));
|
||||
}
|
||||
|
||||
export function _($translate, text, params = []) {
|
||||
text = $translate.instant(text);
|
||||
|
||||
for (let i = 0; i < params.length; i++) {
|
||||
text = text.replace('%s', params[i]);
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
|
@ -1,14 +1,8 @@
|
|||
// app global css in SCSS form
|
||||
@import './icons.scss';
|
||||
|
||||
.body--dark {
|
||||
.q-card--dark {
|
||||
box-shadow: 0 1px 5px rgba(0, 0, 0, 0.2), 0 2px 2px rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
.q-layout__shadow::after {
|
||||
box-shadow: 0 0 10px 2px rgba(0, 0, 0, 0.2), 0 0px 10px rgba(0, 0, 0, 0.24) !important;
|
||||
}
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.link {
|
||||
|
|
|
@ -23,8 +23,11 @@ $negative: #c10015;
|
|||
$info: #31ccec;
|
||||
$warning: #f2c037;
|
||||
|
||||
$color-spacer-light: rgba(255, 255, 255, .12);
|
||||
$color-spacer:rgba(255, 255, 255, .3);
|
||||
$color-spacer-light: rgba(255, 255, 255, 0.12);
|
||||
$color-spacer: rgba(255, 255, 255, 0.3);
|
||||
$border-thin-light: 1px solid $color-spacer-light;
|
||||
|
||||
$dark-shadow-color: #000;
|
||||
$layout-shadow-dark: 0 0 10px 2px rgba(0, 0, 0, 0.2), 0 0px 10px rgba(0, 0, 0, 0.24);
|
||||
|
||||
$spacing-md: 16px;
|
||||
|
|
|
@ -30,6 +30,7 @@ export default {
|
|||
rowAdded: 'Row added',
|
||||
rowRemoved: 'Row removed',
|
||||
pleaseWait: 'Please wait...',
|
||||
noPinnedModules: 'You have dont have any pinned modules',
|
||||
},
|
||||
moduleIndex: {
|
||||
allModules: 'All modules',
|
||||
|
@ -296,7 +297,7 @@ export default {
|
|||
},
|
||||
invoiceOut: {
|
||||
pageTitles: {
|
||||
invoiceOuts: 'InvoiceOuts',
|
||||
invoiceOuts: 'Invoices Out',
|
||||
list: 'List',
|
||||
createInvoiceOut: 'Create invoice out',
|
||||
summary: 'Summary',
|
||||
|
|
|
@ -30,6 +30,7 @@ export default {
|
|||
rowAdded: 'Fila añadida',
|
||||
rowRemoved: 'Fila eliminada',
|
||||
pleaseWait: 'Por favor, espera...',
|
||||
noPinnedModules: 'No has fijado ningún módulo',
|
||||
},
|
||||
moduleIndex: {
|
||||
allModules: 'Todos los módulos',
|
||||
|
|
|
@ -1,48 +0,0 @@
|
|||
import { jest, describe, expect, it, beforeAll } from '@jest/globals';
|
||||
import { createWrapper, axios } from 'app/tests/jest/jestHelpers';
|
||||
import ClaimDescriptorMenu from '../Card/ClaimDescriptorMenu.vue';
|
||||
|
||||
const mockPush = jest.fn();
|
||||
|
||||
jest.mock('vue-router', () => ({
|
||||
useRouter: () => ({
|
||||
push: mockPush,
|
||||
currentRoute: {
|
||||
value: {
|
||||
params: {
|
||||
id: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
}));
|
||||
|
||||
describe('ClaimDescriptorMenu', () => {
|
||||
let vm;
|
||||
beforeAll(() => {
|
||||
vm = createWrapper(ClaimDescriptorMenu, {
|
||||
propsData: {
|
||||
claim: {
|
||||
id: 1
|
||||
}
|
||||
}
|
||||
}).vm;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('deleteClaim()', () => {
|
||||
it('should delete the claim', async () => {
|
||||
jest.spyOn(axios, 'delete').mockResolvedValue({ data: true });
|
||||
jest.spyOn(vm.quasar, 'notify');
|
||||
|
||||
await vm.deleteClaim();
|
||||
|
||||
expect(vm.quasar.notify).toHaveBeenCalledWith(expect.objectContaining(
|
||||
{ 'type': 'positive' }
|
||||
));
|
||||
});
|
||||
});
|
||||
});
|
|
@ -21,9 +21,16 @@ const userLocale = computed({
|
|||
|
||||
if (value === 'en') value = 'en-GB';
|
||||
|
||||
import(`quasar/lang/${value}`).then((language) => {
|
||||
Quasar.lang.set(language.default);
|
||||
});
|
||||
// FIXME: Dynamic imports from absolute paths are not compatible with vite:
|
||||
// https://github.com/rollup/plugins/tree/master/packages/dynamic-import-vars#limitations
|
||||
try {
|
||||
const langList = import.meta.glob('../../node_modules/quasar/lang/*.mjs');
|
||||
langList[`../../node_modules/quasar/lang/${value}.mjs`]().then((lang) => {
|
||||
Quasar.lang.set(lang.default);
|
||||
});
|
||||
} catch (error) {
|
||||
//
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -41,25 +48,29 @@ const password = ref('');
|
|||
const keepLogin = ref(true);
|
||||
|
||||
async function onSubmit() {
|
||||
const { data } = await axios.post('Accounts/login', {
|
||||
user: username.value,
|
||||
password: password.value,
|
||||
});
|
||||
try {
|
||||
const { data } = await axios.post('Accounts/login', {
|
||||
user: username.value,
|
||||
password: password.value,
|
||||
});
|
||||
|
||||
if (!data) return;
|
||||
if (!data) return;
|
||||
|
||||
await session.login(data.token, keepLogin.value);
|
||||
await session.login(data.token, keepLogin.value);
|
||||
|
||||
quasar.notify({
|
||||
message: t('login.loginSuccess'),
|
||||
type: 'positive',
|
||||
});
|
||||
quasar.notify({
|
||||
message: t('login.loginSuccess'),
|
||||
type: 'positive',
|
||||
});
|
||||
|
||||
const currentRoute = router.currentRoute.value;
|
||||
if (currentRoute.query && currentRoute.query.redirect) {
|
||||
router.push(currentRoute.query.redirect);
|
||||
} else {
|
||||
router.push({ name: 'Dashboard' });
|
||||
const currentRoute = router.currentRoute.value;
|
||||
if (currentRoute.query && currentRoute.query.redirect) {
|
||||
router.push(currentRoute.query.redirect);
|
||||
} else {
|
||||
router.push({ name: 'Dashboard' });
|
||||
}
|
||||
} catch (error) {
|
||||
//
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@ -70,7 +81,15 @@ async function onSubmit() {
|
|||
<q-page id="login">
|
||||
<q-page-sticky position="top-right">
|
||||
<q-toolbar>
|
||||
<q-btn :label="t('globals.language')" icon="translate" color="primary" size="sm" flat rounded>
|
||||
<q-btn
|
||||
id="switchLanguage"
|
||||
:label="t('globals.language')"
|
||||
icon="translate"
|
||||
color="primary"
|
||||
size="sm"
|
||||
flat
|
||||
rounded
|
||||
>
|
||||
<q-menu auto-close>
|
||||
<q-list dense>
|
||||
<q-item @click="userLocale = 'en'" :active="userLocale == 'en'" v-ripple clickable>
|
||||
|
|
|
@ -1,71 +0,0 @@
|
|||
import { jest, describe, expect, it, beforeAll } from '@jest/globals';
|
||||
import { createWrapper, axios } from 'app/tests/jest/jestHelpers';
|
||||
import TicketBoxing from '../TicketBoxing.vue';
|
||||
|
||||
const mockPush = jest.fn();
|
||||
|
||||
jest.mock('vue-router', () => ({
|
||||
useRouter: () => ({
|
||||
push: mockPush,
|
||||
currentRoute: {
|
||||
value: {
|
||||
params: {
|
||||
id: 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}),
|
||||
}));
|
||||
|
||||
// #4836 - Investigate how to test q-drawer outside
|
||||
// q-layout or how to teleport q-drawer inside
|
||||
xdescribe('TicketBoxing', () => {
|
||||
let vm;
|
||||
beforeAll(() => {
|
||||
vm = createWrapper(TicketBoxing).vm;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('getVideoList()', () => {
|
||||
it('should when response videoList use to list', async () => {
|
||||
const expeditionId = 1;
|
||||
const timed = {
|
||||
min: 1,
|
||||
max: 2
|
||||
}
|
||||
const videoList = [
|
||||
"2022-01-01T01-01-00.mp4",
|
||||
"2022-02-02T02-02-00.mp4",
|
||||
"2022-03-03T03-03-00.mp4",
|
||||
]
|
||||
|
||||
jest.spyOn(axios, 'get').mockResolvedValue({ data: videoList });
|
||||
jest.spyOn(vm.quasar, 'notify');
|
||||
|
||||
await vm.getVideoList(expeditionId, timed);
|
||||
|
||||
expect(vm.videoList.length).toEqual(videoList.length);
|
||||
expect(vm.slide).toEqual(videoList.reverse()[0]);
|
||||
});
|
||||
|
||||
it('should if not have video show notify', async () => {
|
||||
const expeditionId = 1;
|
||||
const timed = {
|
||||
min: 1,
|
||||
max: 2
|
||||
}
|
||||
|
||||
jest.spyOn(axios, 'get').mockResolvedValue({ data: [] });
|
||||
jest.spyOn(vm.quasar, 'notify')
|
||||
|
||||
await vm.getVideoList(expeditionId, timed);
|
||||
|
||||
expect(vm.quasar.notify).toHaveBeenCalledWith(expect.objectContaining(
|
||||
{ 'type': 'negative' }
|
||||
));
|
||||
});
|
||||
});
|
||||
});
|
|
@ -35,7 +35,7 @@ export default route(function (/* { store, ssrContext } */) {
|
|||
// Leave this as is and make changes in quasar.conf.js instead!
|
||||
// quasar.conf.js -> build -> vueRouterMode
|
||||
// quasar.conf.js -> build -> publicPath
|
||||
history: createHistory(process.env.MODE === 'ssr' ? void 0 : process.env.VUE_ROUTER_BASE),
|
||||
history: createHistory(process.env.VUE_ROUTER_BASE),
|
||||
});
|
||||
|
||||
Router.beforeEach(async (to, from, next) => {
|
||||
|
|
|
@ -30,7 +30,7 @@ const routes = [
|
|||
worker,
|
||||
invoiceOut,
|
||||
{
|
||||
path: '/:pathMatch(.*)*',
|
||||
path: '/:catchAll(.*)*',
|
||||
name: 'NotFound',
|
||||
component: () => import('../pages/NotFound.vue'),
|
||||
},
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
import { store } from 'quasar/wrappers';
|
||||
import { createPinia } from 'pinia';
|
||||
|
||||
/*
|
||||
* If not building with SSR mode, you can
|
||||
* directly export the Store instantiation;
|
||||
*
|
||||
* The function below can be async too; either use
|
||||
* async/await or return a Promise which resolves
|
||||
* with the Store instance.
|
||||
*/
|
||||
|
||||
export default store((/* { ssrContext } */) => {
|
||||
const pinia = createPinia();
|
||||
|
||||
// You can add Pinia plugins here
|
||||
// pinia.use(SomePiniaPlugin)
|
||||
|
||||
return pinia;
|
||||
});
|
|
@ -0,0 +1,10 @@
|
|||
/* eslint-disable */
|
||||
// THIS FEATURE-FLAG FILE IS AUTOGENERATED,
|
||||
// REMOVAL OR CHANGES WILL CAUSE RELATED TYPES TO STOP WORKING
|
||||
import "quasar/dist/types/feature-flag";
|
||||
|
||||
declare module "quasar/dist/types/feature-flag" {
|
||||
interface QuasarFeatureFlags {
|
||||
store: true;
|
||||
}
|
||||
}
|
|
@ -2,6 +2,8 @@
|
|||
describe('Login', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('/#/login');
|
||||
cy.get('#switchLanguage').click();
|
||||
cy.get('div.q-menu div.q-item:nth-child(1)').click();
|
||||
});
|
||||
|
||||
it('should fail to log in using wrong user', () => {
|
||||
|
@ -36,7 +38,7 @@ describe('Login', () => {
|
|||
cy.get('#logout').click();
|
||||
cy.window().its('localStorage').invoke('getItem', 'token').should('not.exist');
|
||||
cy.url().should('contain', '/login');
|
||||
})
|
||||
});
|
||||
|
||||
it(`should get redirected to dashboard since employee can't create tickets`, () => {
|
||||
cy.visit('/#/ticket/create', { failOnStatusCode: false });
|
||||
|
@ -45,7 +47,7 @@ describe('Login', () => {
|
|||
cy.get('input[aria-label="Password"]').type('nightmare');
|
||||
cy.get('button[type="submit"]').click();
|
||||
cy.url().should('contain', '/dashboard');
|
||||
})
|
||||
});
|
||||
|
||||
// ticket creation is not yet implemented, use this test once it is
|
||||
// it(`should get redirected to ticket creation after login since salesPerson can do it`, () => {
|
||||
|
@ -56,4 +58,4 @@ describe('Login', () => {
|
|||
// cy.get('button[type="submit"]').click();
|
||||
// cy.url().should('contain', '/#/ticket/create');
|
||||
// })
|
||||
});
|
||||
});
|
|
@ -1,8 +1,9 @@
|
|||
describe('TicketBoxing', () => {
|
||||
/// <reference types="cypress" />
|
||||
xdescribe('TicketBoxing', () => {
|
||||
beforeEach(() => {
|
||||
const ticketId = 1;
|
||||
cy.viewport(1280, 720)
|
||||
cy.login('developer')
|
||||
cy.viewport(1280, 720);
|
||||
cy.login('developer');
|
||||
cy.visit(`/#/ticket/${ticketId}/boxing`);
|
||||
});
|
||||
|
||||
|
@ -23,16 +24,11 @@ describe('TicketBoxing', () => {
|
|||
method: 'GET',
|
||||
url: '/api/Boxings/*',
|
||||
},
|
||||
[
|
||||
"2022-01-01T01-01-00.mp4",
|
||||
"2022-02-02T02-02-00.mp4",
|
||||
"2022-03-03T03-03-00.mp4",
|
||||
]
|
||||
['2022-01-01T01-01-00.mp4', '2022-02-02T02-02-00.mp4', '2022-03-03T03-03-00.mp4']
|
||||
).as('getVideoList');
|
||||
cy.get('.q-list > :nth-child(3)').click();
|
||||
|
||||
cy.get('.q-list > :nth-child(1)').should('be.visible');
|
||||
cy.get('.q-list > :nth-child(2)').should('be.visible');
|
||||
|
||||
});
|
||||
});
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
// DO NOT REMOVE
|
||||
// Imports Quasar Cypress AE predefined commands
|
||||
import { registerCommands } from '@quasar/quasar-app-extension-testing-e2e-cypress';
|
||||
// import { registerCommands } from '@quasar/quasar-app-extension-testing-e2e-cypress';
|
||||
Cypress.Commands.add('login', (user) => {
|
||||
cy.visit('/#/login');
|
||||
cy.request({
|
||||
|
@ -34,10 +34,10 @@ Cypress.Commands.add('login', (user) => {
|
|||
url: '/api/accounts/login',
|
||||
body: {
|
||||
user: user,
|
||||
password: 'nightmare'
|
||||
}
|
||||
}).then(response => {
|
||||
password: 'nightmare',
|
||||
},
|
||||
}).then((response) => {
|
||||
window.localStorage.setItem('token', response.body.token);
|
||||
})
|
||||
})
|
||||
registerCommands();
|
||||
});
|
||||
});
|
||||
// registerCommands();
|
|
@ -14,3 +14,4 @@
|
|||
// ***********************************************************
|
||||
|
||||
import './commands';
|
||||
|
|
@ -1,21 +1,13 @@
|
|||
import { jest, describe, expect, it, beforeAll } from '@jest/globals';
|
||||
import { createWrapper } from 'app/tests/jest/jestHelpers';
|
||||
import App from '../App.vue';
|
||||
import { vi, describe, expect, it, beforeAll } from 'vitest';
|
||||
import { createWrapper } from 'app/test/vitest/helper';
|
||||
import App from 'src/App.vue';
|
||||
import { useSession } from 'src/composables/useSession';
|
||||
|
||||
const mockPush = jest.fn();
|
||||
const mockLoggedIn = jest.fn();
|
||||
const mockDestroy = jest.fn();
|
||||
const mockLoggedIn = vi.fn();
|
||||
const mockDestroy = vi.fn();
|
||||
const session = useSession();
|
||||
|
||||
jest.mock('vue-router', () => ({
|
||||
useRouter: () => ({
|
||||
push: mockPush,
|
||||
currentRoute: { value: 'myCurrentRoute' },
|
||||
}),
|
||||
}));
|
||||
|
||||
jest.mock('src/composables/useSession', () => ({
|
||||
vi.mock('src/composables/useSession', () => ({
|
||||
useSession: () => ({
|
||||
isLoggedIn: mockLoggedIn,
|
||||
destroy: mockDestroy,
|
||||
|
@ -24,6 +16,7 @@ jest.mock('src/composables/useSession', () => ({
|
|||
|
||||
describe('App', () => {
|
||||
let vm;
|
||||
|
||||
beforeAll(() => {
|
||||
const options = {
|
||||
global: {
|
||||
|
@ -34,7 +27,7 @@ describe('App', () => {
|
|||
});
|
||||
|
||||
it('should return a login error message', async () => {
|
||||
jest.spyOn(vm.quasar, 'notify');
|
||||
vi.spyOn(vm.quasar, 'notify');
|
||||
|
||||
session.isLoggedIn.mockReturnValue(false);
|
||||
|
||||
|
@ -54,7 +47,7 @@ describe('App', () => {
|
|||
});
|
||||
|
||||
it('should return an unauthorized error message', async () => {
|
||||
jest.spyOn(vm.quasar, 'notify');
|
||||
vi.spyOn(vm.quasar, 'notify');
|
||||
|
||||
session.isLoggedIn.mockReturnValue(true);
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
import { vi, describe, expect, it, beforeAll } from 'vitest';
|
||||
import { createWrapper, axios } from 'app/test/vitest/helper';
|
||||
import Leftmenu from 'components/LeftMenu.vue';
|
||||
|
||||
import { useNavigationStore } from 'src/stores/useNavigationStore';
|
||||
|
||||
vi.mock('src/router/modules', () => ({
|
||||
default: [
|
||||
{
|
||||
path: '/customer',
|
||||
name: 'Customer',
|
||||
meta: {
|
||||
title: 'customers',
|
||||
icon: 'vn:client',
|
||||
},
|
||||
menus: {
|
||||
main: ['CustomerList', 'CustomerCreate'],
|
||||
card: ['CustomerBasicData'],
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
name: 'CustomerMain',
|
||||
children: [
|
||||
{
|
||||
path: 'list',
|
||||
name: 'CustomerList',
|
||||
meta: {
|
||||
title: 'list',
|
||||
icon: 'view_list',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'create',
|
||||
name: 'CustomerCreate',
|
||||
meta: {
|
||||
title: 'createCustomer',
|
||||
icon: 'vn:addperson',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}));
|
||||
|
||||
describe('Leftmenu', () => {
|
||||
let vm;
|
||||
let navigation;
|
||||
beforeAll(() => {
|
||||
vi.spyOn(axios, 'get').mockResolvedValue({
|
||||
data: [],
|
||||
});
|
||||
|
||||
vm = createWrapper(Leftmenu, {
|
||||
propsData: {
|
||||
source: 'main',
|
||||
},
|
||||
}).vm;
|
||||
|
||||
navigation = useNavigationStore();
|
||||
navigation.fetchPinned = vi.fn().mockReturnValue(Promise.resolve(true));
|
||||
navigation.getModules = vi.fn().mockReturnValue({
|
||||
value: [
|
||||
{
|
||||
name: 'customer',
|
||||
title: 'customer.pageTitles.customers',
|
||||
icon: 'vn:customer',
|
||||
module: 'customer',
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it('should return a proper formated object with two child items', async () => {
|
||||
const expectedMenuItem = [
|
||||
{
|
||||
name: 'CustomerList',
|
||||
title: 'customer.pageTitles.list',
|
||||
icon: 'view_list',
|
||||
},
|
||||
{
|
||||
name: 'CustomerCreate',
|
||||
title: 'customer.pageTitles.createCustomer',
|
||||
icon: 'vn:addperson',
|
||||
},
|
||||
];
|
||||
const firstMenuItem = vm.items[0];
|
||||
expect(firstMenuItem.children).toEqual(expect.arrayContaining(expectedMenuItem));
|
||||
});
|
||||
});
|
|
@ -1,15 +1,6 @@
|
|||
import { jest, describe, expect, it, beforeAll } from '@jest/globals';
|
||||
import { createWrapper, axios } from 'app/tests/jest/jestHelpers';
|
||||
import Paginate from '../PaginateData.vue';
|
||||
|
||||
const mockPush = jest.fn();
|
||||
|
||||
jest.mock('vue-router', () => ({
|
||||
useRouter: () => ({
|
||||
push: mockPush,
|
||||
currentRoute: { value: 'myCurrentRoute' }
|
||||
}),
|
||||
}));
|
||||
import { vi, describe, expect, it, beforeAll, afterEach } from 'vitest';
|
||||
import { createWrapper, axios } from 'app/test/vitest/helper';
|
||||
import Paginate from 'components/PaginateData.vue';
|
||||
|
||||
describe('Paginate', () => {
|
||||
const expectedUrl = '/api/customers';
|
||||
|
@ -19,17 +10,17 @@ describe('Paginate', () => {
|
|||
attrs: {
|
||||
url: expectedUrl,
|
||||
sortBy: 'id DESC',
|
||||
rowsPerPage: 3
|
||||
}
|
||||
rowsPerPage: 3,
|
||||
},
|
||||
};
|
||||
vm = createWrapper(Paginate, options).vm;
|
||||
|
||||
jest.spyOn(axios, 'get').mockResolvedValue({
|
||||
vi.spyOn(axios, 'get').mockResolvedValue({
|
||||
data: [
|
||||
{ id: 1, name: 'Tony Stark' },
|
||||
{ id: 2, name: 'Jessica Jones' },
|
||||
{ id: 3, name: 'Bruce Wayne' },
|
||||
]
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -37,7 +28,7 @@ describe('Paginate', () => {
|
|||
vm.rows = [];
|
||||
vm.pagination.page = 1;
|
||||
vm.hasMoreData = true;
|
||||
})
|
||||
});
|
||||
|
||||
describe('paginate()', () => {
|
||||
it('should call to the paginate() method and set the data on the rows property', async () => {
|
||||
|
@ -46,9 +37,9 @@ describe('Paginate', () => {
|
|||
filter: {
|
||||
order: 'id DESC',
|
||||
limit: 3,
|
||||
skip: 0
|
||||
}
|
||||
}
|
||||
skip: 0,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
await vm.paginate();
|
||||
|
@ -63,9 +54,9 @@ describe('Paginate', () => {
|
|||
filter: {
|
||||
order: 'id DESC',
|
||||
limit: 3,
|
||||
skip: 0
|
||||
}
|
||||
}
|
||||
skip: 0,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
await vm.paginate();
|
||||
|
@ -78,9 +69,9 @@ describe('Paginate', () => {
|
|||
filter: {
|
||||
order: 'id DESC',
|
||||
limit: 3,
|
||||
skip: 3
|
||||
}
|
||||
}
|
||||
skip: 3,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
vm.pagination.page = 2;
|
||||
|
@ -95,7 +86,7 @@ describe('Paginate', () => {
|
|||
describe('onLoad()', () => {
|
||||
it('should call to the done() callback and not increment the pagination', async () => {
|
||||
const index = 1;
|
||||
const done = jest.fn();
|
||||
const done = vi.fn();
|
||||
|
||||
await vm.onLoad(index, done);
|
||||
|
||||
|
@ -113,7 +104,7 @@ describe('Paginate', () => {
|
|||
expect(vm.pagination.page).toEqual(1);
|
||||
|
||||
const index = 1;
|
||||
const done = jest.fn();
|
||||
const done = vi.fn();
|
||||
|
||||
await vm.onLoad(index, done);
|
||||
|
||||
|
@ -122,11 +113,11 @@ describe('Paginate', () => {
|
|||
});
|
||||
|
||||
it('should call to the done() callback with true as argument to finish pagination', async () => {
|
||||
jest.spyOn(axios, 'get').mockResolvedValue({
|
||||
vi.spyOn(axios, 'get').mockResolvedValue({
|
||||
data: [
|
||||
{ id: 1, name: 'Tony Stark' },
|
||||
{ id: 2, name: 'Jessica Jones' }
|
||||
]
|
||||
{ id: 2, name: 'Jessica Jones' },
|
||||
],
|
||||
});
|
||||
|
||||
vm.rows = [
|
||||
|
@ -138,7 +129,7 @@ describe('Paginate', () => {
|
|||
expect(vm.pagination.page).toEqual(1);
|
||||
|
||||
const index = 1;
|
||||
const done = jest.fn();
|
||||
const done = vi.fn();
|
||||
|
||||
vm.hasMoreData = false;
|
||||
|
|
@ -1,23 +1,22 @@
|
|||
import { describe, expect, it, jest } from '@jest/globals';
|
||||
import { axios, flushPromises } from 'app/tests/jest/jestHelpers';
|
||||
import { useRole } from '../useRole';
|
||||
import { vi, describe, expect, it } from 'vitest';
|
||||
import { axios, flushPromises } from 'app/test/vitest/helper';
|
||||
import { useRole } from 'composables/useRole';
|
||||
const role = useRole();
|
||||
|
||||
describe('useRole', () => {
|
||||
|
||||
describe('fetch', () => {
|
||||
it('should call setUser and setRoles of the state with the expected data', async () => {
|
||||
const rolesData = [
|
||||
{
|
||||
role: {
|
||||
name: 'salesPerson'
|
||||
}
|
||||
name: 'salesPerson',
|
||||
},
|
||||
},
|
||||
{
|
||||
role: {
|
||||
name: 'admin'
|
||||
}
|
||||
}
|
||||
name: 'admin',
|
||||
},
|
||||
},
|
||||
];
|
||||
const fetchedUser = {
|
||||
id: 999,
|
||||
|
@ -26,22 +25,22 @@ describe('useRole', () => {
|
|||
lang: 'en',
|
||||
userConfig: {
|
||||
darkMode: false,
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
const expectedUser = {
|
||||
id: 999,
|
||||
name: `T'Challa`,
|
||||
nickname: 'Black Panther',
|
||||
lang: 'en',
|
||||
darkMode: false,
|
||||
}
|
||||
const expectedRoles = ['salesPerson', 'admin']
|
||||
jest.spyOn(axios, 'get').mockResolvedValue({
|
||||
data: { roles: rolesData, user: fetchedUser }
|
||||
};
|
||||
const expectedRoles = ['salesPerson', 'admin'];
|
||||
vi.spyOn(axios, 'get').mockResolvedValue({
|
||||
data: { roles: rolesData, user: fetchedUser },
|
||||
});
|
||||
|
||||
jest.spyOn(role.state, 'setUser');
|
||||
jest.spyOn(role.state, 'setRoles');
|
||||
vi.spyOn(role.state, 'setUser');
|
||||
vi.spyOn(role.state, 'setRoles');
|
||||
|
||||
role.fetch();
|
||||
|
||||
|
@ -50,19 +49,20 @@ describe('useRole', () => {
|
|||
expect(role.state.setUser).toHaveBeenCalledWith(expectedUser);
|
||||
expect(role.state.setRoles).toHaveBeenCalledWith(expectedRoles);
|
||||
|
||||
role.state.setRoles([])
|
||||
role.state.setRoles([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('hasAny', () => {
|
||||
it('should return true if a role matched', async () => {
|
||||
role.state.setRoles(['admin'])
|
||||
role.state.setRoles(['admin']);
|
||||
const hasRole = role.hasAny(['admin']);
|
||||
|
||||
await flushPromises();
|
||||
|
||||
expect(hasRole).toBe(true);
|
||||
|
||||
role.state.setRoles([])
|
||||
role.state.setRoles([]);
|
||||
});
|
||||
|
||||
it('should return false if no roles matched', async () => {
|
||||
|
@ -73,4 +73,4 @@ describe('useRole', () => {
|
|||
expect(hasRole).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,7 +1,7 @@
|
|||
import { describe, expect, it, jest } from '@jest/globals';
|
||||
import { useSession } from '../useSession';
|
||||
import { useState } from '../useState';
|
||||
import { axios } from 'app/tests/jest/jestHelpers';
|
||||
import { vi, describe, expect, it } from 'vitest';
|
||||
import { axios } from 'app/test/vitest/helper';
|
||||
import { useSession } from 'composables/useSession';
|
||||
import { useState } from 'composables/useState';
|
||||
|
||||
const session = useSession();
|
||||
const state = useState();
|
||||
|
@ -9,7 +9,7 @@ const state = useState();
|
|||
describe('session', () => {
|
||||
describe('getToken / setToken', () => {
|
||||
it('should return an empty string if no token is found in local or session storage', async () => {
|
||||
const expectedToken = ''
|
||||
const expectedToken = '';
|
||||
|
||||
const token = session.getToken();
|
||||
|
||||
|
@ -17,11 +17,11 @@ describe('session', () => {
|
|||
});
|
||||
|
||||
it('should return the token stored in local or session storage', async () => {
|
||||
const expectedToken = 'myToken'
|
||||
const expectedToken = 'myToken';
|
||||
const data = {
|
||||
token: expectedToken,
|
||||
keepLogin: false
|
||||
}
|
||||
keepLogin: false,
|
||||
};
|
||||
session.setToken(data);
|
||||
|
||||
const token = session.getToken();
|
||||
|
@ -38,23 +38,22 @@ describe('session', () => {
|
|||
nickname: 'Black Panther',
|
||||
lang: 'en',
|
||||
darkMode: false,
|
||||
}
|
||||
};
|
||||
const expectedUser = {
|
||||
id: 0,
|
||||
name: '',
|
||||
nickname: '',
|
||||
lang: '',
|
||||
darkMode: null,
|
||||
}
|
||||
};
|
||||
let user = state.getUser();
|
||||
|
||||
localStorage.setItem('token', 'tokenToBeGone');
|
||||
state.setUser(previousUser)
|
||||
state.setUser(previousUser);
|
||||
|
||||
expect(localStorage.getItem('token')).toEqual('tokenToBeGone');
|
||||
expect(user.value).toEqual(previousUser);
|
||||
|
||||
|
||||
session.destroy();
|
||||
|
||||
user = state.getUser();
|
||||
|
@ -71,29 +70,29 @@ describe('session', () => {
|
|||
lang: 'en',
|
||||
userConfig: {
|
||||
darkMode: false,
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
const rolesData = [
|
||||
{
|
||||
role: {
|
||||
name: 'salesPerson'
|
||||
}
|
||||
name: 'salesPerson',
|
||||
},
|
||||
},
|
||||
{
|
||||
role: {
|
||||
name: 'admin'
|
||||
}
|
||||
}
|
||||
name: 'admin',
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
it('should fetch the user roles and then set token in the sessionStorage', async () => {
|
||||
const expectedRoles = ['salesPerson', 'admin']
|
||||
jest.spyOn(axios, 'get').mockResolvedValue({
|
||||
data: { roles: rolesData, user: expectedUser }
|
||||
const expectedRoles = ['salesPerson', 'admin'];
|
||||
vi.spyOn(axios, 'get').mockResolvedValue({
|
||||
data: { roles: rolesData, user: expectedUser },
|
||||
});
|
||||
|
||||
const expectedToken = 'mySessionToken'
|
||||
const keepLogin = false
|
||||
const expectedToken = 'mySessionToken';
|
||||
const keepLogin = false;
|
||||
|
||||
await session.login(expectedToken, keepLogin);
|
||||
|
||||
|
@ -105,17 +104,17 @@ describe('session', () => {
|
|||
expect(localToken).toBeNull();
|
||||
expect(sessionToken).toEqual(expectedToken);
|
||||
|
||||
session.destroy() // this clears token and user for any other test
|
||||
session.destroy(); // this clears token and user for any other test
|
||||
});
|
||||
|
||||
it('should fetch the user roles and then set token in the localStorage', async () => {
|
||||
const expectedRoles = ['salesPerson', 'admin']
|
||||
jest.spyOn(axios, 'get').mockResolvedValue({
|
||||
data: { roles: rolesData, user: expectedUser }
|
||||
const expectedRoles = ['salesPerson', 'admin'];
|
||||
vi.spyOn(axios, 'get').mockResolvedValue({
|
||||
data: { roles: rolesData, user: expectedUser },
|
||||
});
|
||||
|
||||
const expectedToken = 'myLocalToken'
|
||||
const keepLogin = true
|
||||
const expectedToken = 'myLocalToken';
|
||||
const keepLogin = true;
|
||||
|
||||
await session.login(expectedToken, keepLogin);
|
||||
|
||||
|
@ -127,7 +126,7 @@ describe('session', () => {
|
|||
expect(localToken).toEqual(expectedToken);
|
||||
expect(sessionToken).toBeNull();
|
||||
|
||||
session.destroy() // this clears token and user for any other test
|
||||
session.destroy(); // this clears token and user for any other test
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,31 @@
|
|||
import { vi, describe, expect, it, beforeAll, afterEach } from 'vitest';
|
||||
import { createWrapper, axios } from 'app/test/vitest/helper';
|
||||
import ClaimDescriptorMenu from 'pages/Claim/Card/ClaimDescriptorMenu.vue';
|
||||
|
||||
describe('ClaimDescriptorMenu', () => {
|
||||
let vm;
|
||||
beforeAll(() => {
|
||||
vm = createWrapper(ClaimDescriptorMenu, {
|
||||
propsData: {
|
||||
claim: {
|
||||
id: 1,
|
||||
},
|
||||
},
|
||||
}).vm;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('deleteClaim()', () => {
|
||||
it('should delete the claim', async () => {
|
||||
vi.spyOn(axios, 'delete').mockResolvedValue({ data: true });
|
||||
vi.spyOn(vm.quasar, 'notify');
|
||||
|
||||
await vm.deleteClaim();
|
||||
|
||||
expect(vm.quasar.notify).toHaveBeenCalledWith(expect.objectContaining({ type: 'positive' }));
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,15 +1,6 @@
|
|||
import { jest, describe, expect, it, beforeAll } from '@jest/globals';
|
||||
import { createWrapper, axios } from 'app/tests/jest/jestHelpers';
|
||||
import Login from '../LoginMain.vue';
|
||||
|
||||
const mockPush = jest.fn();
|
||||
|
||||
jest.mock('vue-router', () => ({
|
||||
useRouter: () => ({
|
||||
push: mockPush,
|
||||
currentRoute: { value: 'myCurrentRoute' }
|
||||
}),
|
||||
}));
|
||||
import { vi, describe, expect, it, beforeAll, afterEach } from 'vitest';
|
||||
import { createWrapper, axios } from 'app/test/vitest/helper';
|
||||
import Login from 'pages/Login/LoginMain.vue';
|
||||
|
||||
describe('Login', () => {
|
||||
let vm;
|
||||
|
@ -18,7 +9,7 @@ describe('Login', () => {
|
|||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should successfully set the token into session', async () => {
|
||||
|
@ -29,26 +20,24 @@ describe('Login', () => {
|
|||
lang: 'en',
|
||||
userConfig: {
|
||||
darkMode: false,
|
||||
}
|
||||
}
|
||||
jest.spyOn(axios, 'post').mockResolvedValue({ data: { token: 'token' } });
|
||||
jest.spyOn(axios, 'get').mockResolvedValue({ data: { roles: [], user: expectedUser } });
|
||||
jest.spyOn(vm.quasar, 'notify');
|
||||
},
|
||||
};
|
||||
vi.spyOn(axios, 'post').mockResolvedValue({ data: { token: 'token' } });
|
||||
vi.spyOn(axios, 'get').mockResolvedValue({ data: { roles: [], user: expectedUser } });
|
||||
vi.spyOn(vm.quasar, 'notify');
|
||||
|
||||
expect(vm.session.getToken()).toEqual('');
|
||||
|
||||
await vm.onSubmit();
|
||||
|
||||
expect(vm.session.getToken()).toEqual('token');
|
||||
expect(vm.quasar.notify).toHaveBeenCalledWith(expect.objectContaining(
|
||||
{ 'type': 'positive' }
|
||||
));
|
||||
expect(vm.quasar.notify).toHaveBeenCalledWith(expect.objectContaining({ type: 'positive' }));
|
||||
vm.session.destroy();
|
||||
});
|
||||
|
||||
it('should not set the token into session if any error occurred', async () => {
|
||||
jest.spyOn(axios, 'post').mockReturnValue({ data: null });
|
||||
jest.spyOn(vm.quasar, 'notify');
|
||||
vi.spyOn(axios, 'post').mockReturnValue({ data: null });
|
||||
vi.spyOn(vm.quasar, 'notify');
|
||||
|
||||
await vm.onSubmit();
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
import { vi, describe, expect, it, beforeAll, afterEach } from 'vitest';
|
||||
import { createWrapper, axios } from 'app/test/vitest/helper';
|
||||
import TicketBoxing from 'pages/Ticket/Card/TicketBoxing.vue';
|
||||
|
||||
// #4836 - Investigate how to test q-drawer outside
|
||||
// q-layout or how to teleport q-drawer inside
|
||||
describe.skip('TicketBoxing', () => {
|
||||
let vm;
|
||||
beforeAll(() => {
|
||||
vm = createWrapper(TicketBoxing).vm;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('getVideoList()', () => {
|
||||
it('should when response videoList use to list', async () => {
|
||||
const expeditionId = 1;
|
||||
const timed = {
|
||||
min: 1,
|
||||
max: 2,
|
||||
};
|
||||
const videoList = ['2022-01-01T01-01-00.mp4', '2022-02-02T02-02-00.mp4', '2022-03-03T03-03-00.mp4'];
|
||||
|
||||
vi.spyOn(axios, 'get').mockResolvedValue({ data: videoList });
|
||||
vi.spyOn(vm.quasar, 'notify');
|
||||
|
||||
await vm.getVideoList(expeditionId, timed);
|
||||
|
||||
expect(vm.videoList.length).toEqual(videoList.length);
|
||||
expect(vm.slide).toEqual(videoList.reverse()[0]);
|
||||
});
|
||||
|
||||
it('should if not have video show notify', async () => {
|
||||
const expeditionId = 1;
|
||||
const timed = {
|
||||
min: 1,
|
||||
max: 2,
|
||||
};
|
||||
|
||||
vi.spyOn(axios, 'get').mockResolvedValue({ data: [] });
|
||||
vi.spyOn(vm.quasar, 'notify');
|
||||
|
||||
await vm.getVideoList(expeditionId, timed);
|
||||
|
||||
expect(vm.quasar.notify).toHaveBeenCalledWith(expect.objectContaining({ type: 'negative' }));
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,52 @@
|
|||
import { installQuasar } from '@quasar/quasar-app-extension-testing-unit-vitest';
|
||||
import { mount, flushPromises } from '@vue/test-utils';
|
||||
import { createTestingPinia } from '@pinia/testing';
|
||||
import { vi } from 'vitest';
|
||||
import { i18n } from 'src/boot/i18n';
|
||||
import { Notify, Dialog } from 'quasar';
|
||||
import axios from 'axios';
|
||||
|
||||
installQuasar({
|
||||
plugins: {
|
||||
Notify,
|
||||
Dialog,
|
||||
},
|
||||
});
|
||||
|
||||
const mockPush = vi.fn();
|
||||
vi.mock('vue-router', () => ({
|
||||
useRouter: () => ({
|
||||
push: mockPush,
|
||||
currentRoute: { value: 'myCurrentRoute' },
|
||||
}),
|
||||
useRoute: () => ({
|
||||
matched: [],
|
||||
}),
|
||||
}));
|
||||
|
||||
export function createWrapper(component, options) {
|
||||
const pinia = createTestingPinia({ createSpy: vi.fn, stubActions: false });
|
||||
|
||||
const defaultOptions = {
|
||||
global: {
|
||||
plugins: [i18n, pinia],
|
||||
},
|
||||
};
|
||||
|
||||
const mountOptions = Object.assign({}, defaultOptions);
|
||||
|
||||
if (options instanceof Object) {
|
||||
Object.assign(mountOptions, options);
|
||||
|
||||
if (options.global) {
|
||||
mountOptions.global.plugins = defaultOptions.global.plugins;
|
||||
}
|
||||
}
|
||||
|
||||
const wrapper = mount(component, mountOptions);
|
||||
const vm = wrapper.vm;
|
||||
|
||||
return { vm, wrapper };
|
||||
}
|
||||
|
||||
export { axios, flushPromises };
|
|
@ -0,0 +1 @@
|
|||
// This file will be run before each test file
|
|
@ -1,31 +0,0 @@
|
|||
/// <reference types="cypress" />
|
||||
/* eslint-env node */
|
||||
// ***********************************************************
|
||||
// This example plugins/index.js can be used to load plugins
|
||||
//
|
||||
// You can change the location of this file or turn off loading
|
||||
// the plugins file with the 'pluginsFile' configuration option.
|
||||
//
|
||||
// You can read more here:
|
||||
// https://on.cypress.io/plugins-guide
|
||||
// ***********************************************************
|
||||
|
||||
// This function is called when a project is opened or re-opened (e.g. due to
|
||||
// the project's config changing)
|
||||
|
||||
// cypress/plugins/index.js
|
||||
|
||||
// const {injectDevServer} = require('@quasar/quasar-app-extension-testing-e2e-cypress/cct-dev-server');
|
||||
|
||||
// /**
|
||||
// * @type {Cypress.PluginConfig}
|
||||
// */
|
||||
module.exports = async (on, config) => {
|
||||
// // Enable component testing, you can safely remove this
|
||||
// // if you don't plan to use Cypress for unit tests
|
||||
// if (config.testingType === 'component') {
|
||||
// await injectDevServer(on, config);
|
||||
// }
|
||||
|
||||
return config;
|
||||
};
|
|
@ -1,10 +0,0 @@
|
|||
module.exports = {
|
||||
extends: [
|
||||
// Removes 'no-undef' lint errors for Jest global functions (`describe`, `it`, etc),
|
||||
// add Jest-specific lint rules and Jest plugin
|
||||
// See https://github.com/jest-community/eslint-plugin-jest#recommended
|
||||
'plugin:jest/recommended',
|
||||
// Uncomment following line to apply style rules
|
||||
// 'plugin:jest/style',
|
||||
],
|
||||
};
|
|
@ -1 +0,0 @@
|
|||
coverage/*
|
|
@ -1,32 +0,0 @@
|
|||
import { mount, flushPromises } from '@vue/test-utils';
|
||||
import { installQuasarPlugin } from '@quasar/quasar-app-extension-testing-unit-jest';
|
||||
import { i18n } from 'src/boot/i18n';
|
||||
import { Notify, Dialog } from 'quasar';
|
||||
import axios from 'axios';
|
||||
|
||||
installQuasarPlugin({
|
||||
plugins: {
|
||||
Notify,
|
||||
Dialog,
|
||||
},
|
||||
});
|
||||
|
||||
export function createWrapper(component, options) {
|
||||
const mountOptions = {};
|
||||
|
||||
if (options instanceof Object) Object.assign(mountOptions, options);
|
||||
|
||||
if (mountOptions.global && mountOptions.global.plugins) {
|
||||
mountOptions.global.plugins.push(i18n);
|
||||
} else {
|
||||
if (!mountOptions.global) mountOptions.global = {};
|
||||
mountOptions.global.plugins = [i18n];
|
||||
}
|
||||
|
||||
const wrapper = mount(component, mountOptions);
|
||||
const vm = wrapper.vm;
|
||||
|
||||
return { vm, wrapper };
|
||||
}
|
||||
|
||||
export { axios, flushPromises };
|
|
@ -0,0 +1,31 @@
|
|||
import { defineConfig } from 'vitest/config';
|
||||
import vue from '@vitejs/plugin-vue';
|
||||
import { quasar, transformAssetUrls } from '@quasar/vite-plugin';
|
||||
import jsconfigPaths from 'vite-jsconfig-paths';
|
||||
import VueI18nPlugin from '@intlify/unplugin-vue-i18n/vite';
|
||||
import path from 'path';
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
test: {
|
||||
environment: 'happy-dom',
|
||||
setupFiles: 'test/vitest/setup-file.js',
|
||||
include: [
|
||||
// Matches vitest tests in any subfolder of 'src' or into 'test/vitest/__tests__'
|
||||
// Matches all files with extension 'js', 'jsx', 'ts' and 'tsx'
|
||||
'test/vitest/__tests__/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}',
|
||||
],
|
||||
},
|
||||
plugins: [
|
||||
vue({
|
||||
template: { transformAssetUrls },
|
||||
}),
|
||||
quasar({
|
||||
sassVariables: 'src/quasar-variables.scss',
|
||||
}),
|
||||
VueI18nPlugin({
|
||||
include: path.resolve(__dirname, 'src/i18n/**'),
|
||||
}),
|
||||
jsconfigPaths(),
|
||||
],
|
||||
});
|
Loading…
Reference in New Issue