Configure eslint to read common types in src/types/types.d.ts vue3 - vuejs3

My eslint .eslintrc.js, now properly in the src folder, is the following:
module.exports = {
env: {
browser: true,
commonjs: true,
es2021: true
},
extends: [
'plugin:vue/vue3-recommended',
'standard',
'prettier'
],
parserOptions: {
ecmaVersion: 2020,
parser: '#typescript-eslint/parser',
'ecmaFeatures': {
'jsx': true
}
},
plugins: [
'vue',
'#typescript-eslint'
],
rules: {
'import/no-unresolved': 'error'
},
settings: {
'import/parsers': {
'#typescript-eslint/parser': ['.ts', '.tsx']
},
'import/resolver': {
'typescript': {
'alwaysTryTypes': true,
}
}
}
}
I'm attempting to use eslint-import-resolver-typescript, but the documentation is a bit opaque.
I currently get errors on lines where a externally defined type is used (StepData in this example):
setup() {
const data = inject("StepData") as StepData;
return {
data,
};
},

The answer was the following. In types.d.ts (or other file if you want to have different collections of your custom types):
export interface MyType {
positioner: DOMRect;
content: DOMRect;
arrow: DOMRect;
window: DOMRect;
}
export interface SomeOtherType {
.. and so on
Then in the .vue files, import the types I need for the component:
import type { MyType, SomeOtherType } from "../types/types";
Before I was not using the export keyword and the types just worked without being imported. They have to be imported like this if you use export. It's kind of amazing how you are just expected to know this, the documentation for Typescript or Vue is sorely lacking in examples.

Related

Bootstrap i18n Translation of column headings - TypeError: this.$i18n.t is not a function

Trying to add column headings to a bootstrap table in a Vue 3 project using i18n dependency:
"vue-i18n": "^9.3.0-beta.10",
computed: {
fields() {
return [
{ key: "formID", label: this.transColHeading("status.form_id"), sortable: true }
];
}
},
methods: {
transColHeading(colHeading) {
return this.$i18n.t(colHeading);
},
}
But I am getting the error
TypeError: this.$i18n.t is not a function
Any idea how to make this work?
For info if I console log this.$i18n.locale I get the correct language.

How to configure cypress-sql-server with no cypress.json? (updated)

I'm trying to setup cypress-sql-server, but I'm using version 10.8.0, which does not use cypress.json to configure the environment. All of the setup instructions I've found refer to using cypress.json to configure the plug-in. With the help of u/Fody, I'm closer, but I'm still running into an error:
tasksqlServer:execute, SELECT 'Bob'
CypressError
cy.task('sqlServer:execute') failed with the following error:
The 'task' event has not been registered in the setupNodeEvents method. You must register it before using cy.task()
Fix this in your setupNodeEvents method here:
D:\git\mcare.automation\client\cypress\cypress.config.jsLearn more
node_modules/cypress-sql-server/src/commands/db.js:7:1
5 | }
6 |
> 7 | cy.task('sqlServer:execute', query).then(response => {
| ^
8 | let result = [];
9 |
cypress.config.js
const { defineConfig } = require("cypress");
const sqlServer = require("cypress-sql-server");
module.exports = defineConfig({
e2e: {
setupNodeEvents(on, config) {
// allows db data to be accessed in tests
config.db = {
"userName": "user",
"password": "pass",
"server": "myserver",
"options": {
"database": "mydb",
"encrypt": true,
"rowCollectionOnRequestCompletion": true
}
}
// code from /plugins/index.js
const tasks = sqlServer.loadDBPlugin(config.db);
on('task', tasks);
return config
// implement node event listeners here
},
},
});
testSQL.spec.js
describe('Testing SQL queries', () => {
it("It should return Bob", () => {
cy.sqlServer("SELECT 'Bob'").should('eq', 'Bob');
});
})
My versions:
\cypress> npx cypress --version
Cypress package version: 10.8.0
Cypress binary version: 10.8.0
Electron version: 19.0.8
Bundled Node version:
16.14.2
Suggestions? Is there any more info I can provide to help?
This is the install instruction currently given by cypress-sql-server for Cypress v9
Plugin file
The plug-in can be initialised in your cypress/plugins/index.js file as below.
const sqlServer = require('cypress-sql-server');
module.exports = (on, config) => {
tasks = sqlServer.loadDBPlugin(config.db);
on('task', tasks);
}
Translating that into Cypress v10+
const { defineConfig } = require('cypress')
const sqlServer = require('cypress-sql-server');
module.exports = defineConfig({
e2e: {
setupNodeEvents(on, config) {
// allows db data to be accessed in tests
config.db = {
"userName": "user",
"password": "pass",
"server": "myserver",
"options": {
"database": "mydb",
"encrypt": true,
"rowCollectionOnRequestCompletion": true
}
}
// code from /plugins/index.js
const tasks = sqlServer.loadDBPlugin(config.db);
on('task', tasks);
return config
},
},
})
Other variations work, such as putting the "db": {...} section below the "e2e: {...}" section, but not in the "env": {...} section.
Custom commands
Instructions for Cypress v9
Commands file
The extension provides multiple sets of commands. You can import the ones you need.
Example support/index.js file.
import sqlServer from 'cypress-sql-server';
sqlServer.loadDBCommands();
For Cypress v10+
Just move this code to support/e2e.js
cypress.json is a way to specify Cypress environment variables. Instead of using a cypress.json file, you can use any of the strategies in that link.
If you just wanted to include them in your cypress.config.js, it would look something like this:
const { defineConfig } = require('cypress')
module.exports = defineConfig({
e2e: {
baseUrl: 'http://localhost:1234',
env: {
db: {
// your db values here
}
}
}
})

How to connect google analytics to Nuxt3 app?

I have a problem. I try to connect my Nuxt3 app with Google Analytics.
right now I do it by adding to nuxt.config.ts following code
export default defineNuxtConfig({
buildModules: [
'#nuxtjs/google-analytics'
],
googleAnalytics: {
id: process.env.GOOGLE_ANALYTICS_ID
},
})
but unfortunately I get following error when I try to build my app
ERROR Error compiling template: { 17:53:04
ssr: false,
src: 'C:\\Users\\szczu\\Elektryk\\node_modules\\#nuxtjs\\google-analytics\\lib\\plugin.js',
fileName: 'google-analytics.js',
options: {
dev: true,
debug: {
sendHitTask: true
},
id: undefined
},
filename: 'google-analytics.js',
dst: 'C:/Users/szczu/Elektryk/.nuxt/google-analytics.js'
}
ERROR serialize is not defined 17:53:04
at eval (eval at <anonymous> (node_modules\lodash.template\index.js:1550:12), <anonymous>:7:1)
at compileTemplate (/C:/Users/szczu/Elektryk/node_modules/#nuxt/kit/dist/index.mjs:493:45)
at async /C:/Users/szczu/Elektryk/node_modules/nuxt3/dist/chunks/index.mjs:1296:22
at async Promise.all (index 11)
at async generateApp (/C:/Users/szczu/Elektryk/node_modules/nuxt3/dist/chunks/index.mjs:1295:3)
at async _applyPromised (/C:/Users/szczu/Elektryk/node_modules/perfect-debounce/dist/index.mjs:54:10)
Does anyone have an idea how to fix it?
Try the vue-vtag-next package as a plugin
yarn add --dev vue-gtag-next
Create a plugin file plugins/vue-gtag.client.js
import VueGtag from 'vue-gtag-next'
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.use(VueGtag, {
property: {
id: 'GA_MEASUREMENT_ID'
}
})
})
Late reply, but i would like to add for any future viewers.
The above solution only worked for me when the $router was passed. Please find below sample code.
Please also note:
The package being used, 'vue-gtag' instead of 'vue-gtag-next'.
You have to pass config object instead of property for the 'vue-gtag' package
import VueGtag from 'vue-gtag'
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.use(VueGtag, {
config: {
id: 'GA_MEASUREMENT_ID',
},
}, nuxtApp.$router)
})
found this solution https://github.com/nuxt/framework/discussions/5702
.. And also you may use nuxt.config to provide app.head.script with children attribute on the app level:
import { defineNuxtConfig } from "nuxt";
export default defineNuxtConfig({
app: {
head: {
script: [{ children: 'console.log("test3");' }],
},
},
});
import VueGtag from 'vue-gtag-next'
export default defineNuxtPlugin(async (nuxtApp) => {
const { data: { value: {google_id, google_sv, yandex_id, privacy_policy} } } = await useMyApi("/api/main/site-metriks/");
nuxtApp.vueApp.use(VueGtag, {
property: {
id: google_id
}
})
})
For Nuxt 3:
Install vue-gtm: npm i #gtm-support/vue-gtm
Create file in /plugins/vue-gtm.client.ts
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.use(createGtm({
id: 'GTM-ID',
defer: false, // Script can be set to `defer` to speed up page load at the cost of less accurate results (in case visitor leaves before script is loaded, which is unlikely but possible). Defaults to false, so the script is loaded `async` by default
compatibility: false, // Will add `async` and `defer` to the script tag to not block requests for old browsers that do not support `async`
nonce: '2726c7f26c', // Will add `nonce` to the script tag
enabled: true, // defaults to true. Plugin can be disabled by setting this to false for Ex: enabled: !!GDPR_Cookie (optional)
debug: true, // Whether or not display console logs debugs (optional)
loadScript: true, // Whether or not to load the GTM Script (Helpful if you are including GTM manually, but need the dataLayer functionality in your components) (optional)
vueRouter: useRouter(), // Pass the router instance to automatically sync with router (optional)
//ignoredViews: ['homepage'], // Don't trigger events for specified router names (optional)
trackOnNextTick: false, // Whether or not call trackView in Vue.nextTick
}))
})
Nuxt would automatically pick up this plugin and you're done.

After Custom transformer, typescript still uses reference to old import

I'm using a CustomTransformer to update imports from:
import { global_spacer_form_element } from '#patternfly/react-tokens';
export const disabledLabelClassNameEx = global_spacer_form_element.var;
to
import global_spacer_form_element from '#patternfly/react-tokens/dist/js/global_spacer_form_element';
export const disabledLabelClassNameEx = global_spacer_form_element.var;
However, when using with ts-loader I get the following output (directly from ts-loader):
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.disabledLabelClassNameEx = void 0;
const global_spacer_form_element_1 = __importDefault(require("#patternfly/react-tokens/dist/js/global_spacer_form_element"));
exports.disabledLabelClassNameEx = react_tokens_1.global_spacer_form_element.var;
//# sourceMappingURL=Recipient2.js.map
Instead of using global_spacer_form_element directly, it is using react_tokens_1.global_spacer_form_element.
I suppose there is something missing in the transformer that the typescript compiler is using to build that react_tokens_1 variable.
The transformer is doing the following in its visitor (I'm simplifying the transformer code for the sake of showing the path it takes, full code can be see here):
const visitor: ts.Visitor = (node) => {
if (ts.isSourceFile(node)) {
return ts.visitEachChild(node, visitor, context)
}
if (!ts.isImportDeclaration(node) /* or if the lib name is not '#patternfly/react-tokens' */) {
return node
}
// for simplicity assume we take all NamedImports and the only found is...
const elements = ['global_spacer_form_element']
const importPath = '#patternfly/react-tokens/dist/js/global_spacer_form_element'
return elements.map((e) => {
return ts.factory.createImportDeclaration(
undefined,
undefined,
ts.factory.createImportClause(
false,
ts.factory.createIdentifier(e),
undefined,
),
ts.factory.createStringLiteral(importPath),
)
})
}
My tsconfig.json
{
"compilerOptions": {
"module": "commonjs",
"target": "es6",
"allowJs": true,
"checkJs": false,
"jsx": "react",
"outDir": "./build",
"removeComments": true,
"pretty": true,
"skipLibCheck": true,
"strict": true,
"moduleResolution": "node",
"esModuleInterop": true,
"noImplicitAny": false,
"sourceMap": true,
"resolveJsonModule" : true
},
"include": [
"./src/**/*"
],
"exclude": [
"./node_modules/*",
"**/*.js"
]
}
and finally the ts-loader config:
{
test: /src\/.*\.tsx?$/,
loader: 'ts-loader',
exclude: /(node_modules)/i,
options: {
getCustomTransformers: () => ({
before: [
tsImportPluginFactory({
libraryName: '#patternfly/react-tokens',
libraryDirectory: 'dist/js',
camel2DashComponentName: false
})
]
})
}
Any idea of what else I need to update or what I could check to ensure this transformer works as I am expecting?
edit: Reference to old import is gone, but I didn't notice before that the new import also gets transformed: e.g. from foobar to foobar_1.
The TypeScript compiler has four main phases—parsing, binding, type checking, and emitting. Binding is where the relationships between identifiers are resolved, but transformation happens during the "emitting" phase. So by the time you're transforming it's too late and the compiler has already figured out what identifiers it's going to transform.
One way to do what you want to do, is to traverse all the nodes in the file, find the identifiers that match one of the ones in your import, then recreate those identifiers by returning context.factory.createIdentifier(node.escapedText) in the visitor for that node. That will make the compiler leave the node as-is when emitting.
The trouble though may be figuring out which identifiers in a file reference the named import identifier. Generally I don't recommend using the type checker in transforms because it can lead to unexpected results when there are multiple transformations happening on a file, but you might be able to get away with first checking if the identifier's escapeText matches, then checking if typeChecker.getSymbolAtLocation(node)?.declarations[0] equals the named export identifier found in the original import declaration. Alternatively, I think you would have to implement your own scope analysis.

How to stub or ignore meteor/session in jest env?

Jestjs gives me this error when I am testing a react component:
import {Session} from 'meteor/session' ". The error is "Cannot find module 'meteor/session' "
myTestFile
import PlanSetup from "../../../ui/pages/planSetup/planSetup";
let PlanSetupWrapper;
const PlansetupProps={
name: "string",
budget: "string",
lang: { english: "en",
French : "fr"
}
};
describe('<PlanSetup />', () => {
PlanSetupWrapper = mount(<PlanSetup {...PlansetupProps}/>);
it('All child components renders correctly', () => {
expect(PlanSetupWrapper).toMatchSnapshot();
});
});
**jest.config.js**
module.exports = {
moduleNameMapper: {
"^meteor/(.*)": "<rootDir>/imports/tests/mocks/meteor.js"
},
transform: {
"^.+\\.(js|jsx)?$": "babel-jest",
".+\\.(css|styl|less|sass|scss)$": "/home/megha/Megha/TVStack/dan-tvstack-ui/node_modules/jest-css-modules-transform",
},
moduleFileExtensions: [
'js',
'jsx'
],
modulePaths: [
"<rootDir>/node_modules/"
],
globals: {
"window": true
},
unmockedModulePathPatterns: [
'/^imports\\/.*\\.jsx?$/'
],
setupFiles: [
"<rootDir>/setupTests.js"
]
};
**<rootDir>/imports/tests/mocks/meteor.js**
exports._session = {
__: function(value) { return value }
};
Welcome to Stack Overflow #MeghaRawat. There are a couple of things to consider here.
1) Keeping your components pure
2) Mocking up Meteor services
What this means is that any React components should be as pure as possible, and not reference Meteor - the containers should do that, and pass props to the components.
Jest doesn't know about Meteor, so any Meteor features will need to be stubbed, to prevent the the kind of problems you are encountering.
I may be able to find some code to help you if you need it.

Resources