Using CKEditor in a component with Laravel/Inertia - components

I'd like to use Ckeditor in my Laravel/Inertia project and i can't get it to work. I found a tutorial from LaraTips, but that was written for VueJS-2. I am working with the lastest version Inertia which uses VueJS-3.
I want to use Ckeditor in a separate component, and it (sort of) works, but i can't get the old data to show in the editor. I get an error "Uncaught (in promise) TypeError: Cannot read property 'setData' of undefined at Proxy.modelValue (app.js:29)"
What am i doing wrong?
This is my component:
<template>
<ckeditor :editor="editor" v-model="text" :config="editorConfig"></ckeditor>
</template>
<script>
import ClassicEditor from '#ckeditor/ckeditor5-build-classic';
export default {
data() {
return {
text: "",
editor: ClassicEditor,
editorConfig: {
// The configuration of the editor.
},
}
},
props: {
modelValue: {}
},
setup() {
},
watch: {
modelValue: {
immediate: true,
handler(modelValue) {
this.text = modelValue;
}
},
text(text) {
this.$emit('update:modelValue', text);
}
},
}
</script>
Any suggestions??

I am doing the same tutorial (i am using vueJS-3).
this may work for you:
in app.js include CKEditor:
createInertiaApp({
title: (title) => `${title} - ${appName}`,
resolve: (name) => require(`./Pages/${name}.vue`),
setup({ el, app, props, plugin }) {
return createApp({ render: () => h(app, props) })
.use(plugin)
.use( CKEditor)
.mixin({ methods: { route } })
.mount(el);
},
});
In Components/CkEditor.vue check what are you emitting
look for this this.$emit("input", text);
<template>
<ckeditor :editor="editor" v-model="text" :config="editorConfig"></ckeditor>
</template>
<script>
import ClasicEditor from "#ckeditor/ckeditor5-build-classic";
export default {
props: {
value: {},
},
data() {
return {
text: "",
editor: ClasicEditor,
editorConfig: {
// The configuration of the editor.
},
};
},
watch: {
value:{
inmediate: true,
handler(value){
this.text = value;
}
},
text(text) {
this.$emit("input", text);
},
},
};
</script>
let me know if that worked for you

I looked at the answer here, and below is what worked for me:
Hope this helps! :)
I am using laravel/inertia with vue 3.
app.js
import './bootstrap';
import '../css/app.css';
import { createApp, h } from 'vue';
import { createInertiaApp } from '#inertiajs/inertia-vue3';
import { InertiaProgress } from '#inertiajs/progress';
import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers';
import { ZiggyVue } from '../../vendor/tightenco/ziggy/dist/vue.m';
import { createPinia } from 'pinia';
import { _t } from './Utilities/translations';
import CKEditor from '#ckeditor/ckeditor5-vue';
const appName =
window.document.getElementsByTagName('title')[0]?.innerText || 'Laravel';
createInertiaApp({
title: (title) => `${title} - ${appName}`,
resolve: (name) =>
resolvePageComponent(
`./Pages/${name}.vue`,
import.meta.glob('./Pages/**/*.vue')
),
setup({ el, app, props, plugin }) {
const vue_app = createApp({ render: () => h(app, props) });
vue_app.use(plugin);
vue_app.use(ZiggyVue, Ziggy);
vue_app.use(createPinia());
// Register all base components globally
const components = import.meta.globEager('./Components/Base/*.vue');
for (const path in components) {
let componentName;
if (path.split) {
const split_componentName = path.split('/').pop();
if (split_componentName) {
componentName = split_componentName.replace(/\.\w+$/, '');
vue_app.component(componentName, components[path].default);
}
}
}
vue_app.config.globalProperties.$_t = _t;
vue_app.use(CKEditor);
vue_app.mount(el);
return vue_app;
}
});
InertiaProgress.init({ color: '#4B5563' });
CKEditor Component:
<template>
<div id="app">
<ckeditor
v-model="editor_data"
:editor="editor"
:config="editor_config"
></ckeditor>
</div>
</template>
<script setup lang="ts">
import { reactive, ref } from '#vue/reactivity';
import * as editor from '#ckeditor/ckeditor5-build-classic';
const editor_data = ref('');
const editor_config = {};
</script>

Related

Adminjs adding custom reactjs components to my resource on adminjs

I am using adminjs for the first time and I have written my own custom component, but adding it to the resource keeps producing an error that says "You have to implement action component for your Action" Here is my resource:
const {Patient} = require('./../models/Patient')
const Components = require('./../components/components')
const { Patient } = require('./../models/Patient')
const Components = require('./../components/components')
const PatientResource = {
resource: Patient,
options: {
actions: {
consultation: {
actionType: 'record',
component: Components.MyCustomAction,
handler: (request, response, context) => {
const { record, currentAdmin } = context
return {
record: record.toJSON(currentAdmin),
msg: 'Hello world',
}
},
},
isAccessible: ({ currentAdmin }) => {
action: if (currentAdmin.role_id === 5) {
return false
} else {
return true
}
},
},
navigation: 'Manage Patients',
listProperties: [
'id',
'last_name',
'first_name',
'sex',
'marital_status',
'blood_group',
'genotype',
'existing_health_condition',
],
},
}
module.exports = { PatientResource }
And this is my custom component:
import React from 'react'
import { Box, H3 } from '#adminjs/design-system'
import { ActionProps } from 'adminjs'
const MyCustomActionComponent = (props: ActionProps) => {
const { record } = props
return (
<Box flex>
<Box
variant='white'
width={1 / 2}
boxShadow='card'
mr='xxl'
flexShrink={0}
>
<H3>Example of a simple page</H3>
<p>Where you can put almost everything</p>
<p>like this: </p>
<p>
<img
src='https://i.redd.it/rd39yuiy9ns21.jpg'
alt='stupid cat'
width={300}
/>
</p>
</Box>
<p> Or (more likely), operate on a returned record:</p>
<Box overflowX='auto'> {JSON.stringify(record)}</Box>
</Box>
)
}
module.exports = { MyCustomActionComponent }
I tried to add the component to my custom defined action "Consultation", Hence I expected to see a custom page which i have designed using react as in "mycustomAction" above

Generate one single file for each entry with Vite

Basically what I need is generate one single file that contain all vendors and dependencies for each entry..
export default defineConfig({
plugins: [ react() ],
build: {
rollupOptions: {
input: {
popup: path.resolve(pagesDirectory, 'popup', 'index.html'),
background: path.resolve(pagesDirectory, 'background', 'index.ts'),
content_script: path.resolve(pagesDirectory, 'content_script', 'ContentScript.tsx')
},
output: {
entryFileNames: 'src/pages/[name]/index.js',
chunkFileNames: isDevelopment ? 'assets/js/[name].js' : 'assets/js/[name].[hash].js',
assetFileNames: (assetInfo) => {
const { dir, name: _name } = path.parse(assetInfo.name);
const assetFolder = getLastElement(dir.split('/'));
const name = assetFolder + firstUpperCase(_name);
return `assets/[ext]/${name}.chunk.[ext]`;
}
}
}
}})
In this case.. will be one file for popup, background and content_script
Here is one example of ContentScript.tsx file...
import * as React from 'react';
import { createRoot } from 'react-dom/client';
import Badge from './badge';
function init(query: string) {
const appContainer = document.querySelector('#search') as HTMLElement;
if (!appContainer) {
throw new Error('Can not find AppContainer');
}
const rootElement = document.createElement('div');
rootElement.setAttribute('id', 'web-answer-content-script');
appContainer.insertBefore(rootElement, appContainer.firstChild);
const root = createRoot(rootElement, {});
root.render(
<React.StrictMode>
<Badge query={query} />
</React.StrictMode>
);
}
const searchParameters = new URLSearchParams(window.location.search);
if (searchParameters.has('q')) {
const query = searchParameters.get('q');
init(query);
}
import MessageSender = chrome.runtime.MessageSender;
function handleMessageReceived(message: string, sender: MessageSender) {
console.log('>>> MESSAGE RECEIVED', message, sender);
}
chrome.runtime.onMessage.addListener(handleMessageReceived);
With this configuration I'm getting this..
and my content_scripts/index.js ..
import { j as n, c as a, r as c } from '../../../assets/jsx-dev-runtime.a077470a.js';
// ..rest of the code...
As you can see.. I don't want this import... statement ..

next-i18next Jest Testing with useTranslation

Testing libs...always fun. I am using next-i18next within my NextJS project. We are using the useTranslation hook with namespaces.
When I run my test there is a warning:
console.warn
react-i18next:: You will need to pass in an i18next instance by using initReactI18next
> 33 | const { t } = useTranslation(['common', 'account']);
| ^
I have tried the setup from the react-i18next test examples without success. I have tried this suggestion too.
as well as just trying to mock useTranslation without success.
Is there a more straightforward solution to avoid this warning? The test passes FWIW...
test('feature displays error', async () => {
const { findByTestId, findByRole } = render(
<I18nextProvider i18n={i18n}>
<InviteCollectEmails onSubmit={jest.fn()} />
</I18nextProvider>,
{
query: {
orgId: 666,
},
}
);
const submitBtn = await findByRole('button', {
name: 'account:organization.invite.copyLink',
});
fireEvent.click(submitBtn);
await findByTestId('loader');
const alert = await findByRole('alert');
within(alert).getByText('failed attempt');
});
Last, is there a way to have the translated plain text be the outcome, instead of the namespaced: account:account:organization.invite.copyLink?
Use the following snippet before the describe block OR in beforeEach() to mock the needful.
jest.mock("react-i18next", () => ({
useTranslation: () => ({ t: key => key }),
}));
Hope this helps. Peace.
use this for replace render function.
import { render, screen } from '#testing-library/react'
import DarkModeToggleBtn from '../../components/layout/DarkModeToggleBtn'
import { appWithTranslation } from 'next-i18next'
import { NextRouter } from 'next/router'
jest.mock('react-i18next', () => ({
I18nextProvider: jest.fn(),
__esmodule: true,
}))
const createProps = (locale = 'en', router: Partial<NextRouter> = {}) => ({
pageProps: {
_nextI18Next: {
initialLocale: locale,
userConfig: {
i18n: {
defaultLocale: 'en',
locales: ['en', 'fr'],
},
},
},
} as any,
router: {
locale: locale,
route: '/',
...router,
},
} as any)
const Component = appWithTranslation(() => <DarkModeToggleBtn />)
const defaultRenderProps = createProps()
const renderComponent = (props = defaultRenderProps) => render(
<Component {...props} />
)
describe('', () => {
it('', () => {
renderComponent()
expect(screen.getByRole("button")).toHaveTextContent("")
})
})
I used a little bit more sophisticated approach than mocking to ensure all the functions work the same both in testing and production environment.
First, I create a testing environment:
// testing/env.ts
import i18next, { i18n } from "i18next";
import JSDomEnvironment from "jest-environment-jsdom";
import { initReactI18next } from "react-i18next";
declare global {
var i18nInstance: i18n;
}
export default class extends JSDomEnvironment {
async setup() {
await super.setup();
/* The important part start */
const i18nInstance = i18next.createInstance();
await i18nInstance.use(initReactI18next).init({
lng: "cimode",
resources: {},
});
this.global.i18nInstance = i18nInstance;
/* The important part end */
}
}
I add this environment in jest.config.ts:
// jest.config.ts
export default {
// ...
testEnvironment: "testing/env.ts",
};
Sample component:
// component.tsx
import { useTranslation } from "next-i18next";
export const Component = () => {
const { t } = useTranslation();
return <div>{t('foo')}</div>
}
And later on I use it in tests:
// component.test.tsx
import { setI18n } from "react-i18next";
import { create, act, ReactTestRenderer } from "react-test-renderer";
import { Component } from "./component";
it("renders Component", () => {
/* The important part start */
setI18n(global.i18nInstance);
/* The important part end */
let root: ReactTestRenderer;
act(() => {
root = create(<Component />);
});
expect(root.toJSON()).toMatchSnapshot();
});
I figured out how to make the tests work with an instance of i18next using the renderHook function and the useTranslation hook from react-i18next based on the previous answers and some research.
This is the Home component I wanted to test:
import { useTranslation } from 'next-i18next';
const Home = () => {
const { t } = useTranslation("");
return (
<main>
<div>
<h1> {t("welcome", {ns: 'home'})}</h1>
</div>
</main>
)
};
export default Home;
First, we need to create a setup file for jest so we can start an i18n instance and import the translations to the configuration. test/setup.ts
import i18n from "i18next";
import { initReactI18next } from "react-i18next";
import homeES from '#/public/locales/es/home.json';
import homeEN from '#/public/locales/en/home.json';
i18n.use(initReactI18next).init({
lng: "es",
resources: {
en: {
home: homeEN,
},
es: {
home: homeES,
}
},
fallbackLng: "es",
debug: false,
});
export default i18n;
Then we add the setup file to our jest.config.js:
setupFilesAfterEnv: ["<rootDir>/test/setup.ts"]
Now we can try our tests using the I18nextProvider and the useTranslation hook:
import '#testing-library/jest-dom/extend-expect';
import { cleanup, render, renderHook } from '#testing-library/react';
import { act } from 'react-dom/test-utils';
import { I18nextProvider, useTranslation } from 'react-i18next';
import Home from '.';
describe("Index page", (): void => {
afterEach(cleanup);
it("should render properly in Spanish", (): void => {
const t = renderHook(() => useTranslation());
const component = render(
<I18nextProvider i18n={t.result.current.i18n}>
<Home / >
</I18nextProvider>
);
expect(component.getByText("Bienvenido a Pocky")).toBeInTheDocument();
});
it("should render properly in English", (): void => {
const t = renderHook(() => useTranslation());
act(() => {
t.result.current.i18n.changeLanguage("en");
});
const component = render(
<I18nextProvider i18n={t.result.current.i18n}>
<Home/>
</I18nextProvider>
);
expect(component.getByText("Welcome to Pocky")).toBeInTheDocument();
});
});
Here we used the I18nextProvider and send the i18n instance using the useTranslation hook. after that the translations were loaded without problems in the Home component.
We can also change the selected language running the changeLanguage() function and test the other translations.

GSAP timeline needed on every page in Gatsby

My Gatsby site use the same GSAP timeline on every page, so I want to stay DRY and my idea is to include my timeline in my Layout component in that order.
But I don't know how to pass refs that I need between children and layout using forwardRef.
In short, I don't know how to handle the sectionsRef part between pages and layout.
sectionsRef is dependant of the page content (children) but is needed in the timeline living in layout.
How can I share sectionsRef between these two (I tried many things but always leading to errors)?
Here's a codesandbox without the refs in the Layout:
https://codesandbox.io/s/jolly-almeida-njt2e?file=/src/pages/index.js
And the sandbox with the refs in the layout:
https://codesandbox.io/s/pensive-varahamihira-tc45m?file=/src/pages/index.js
Here's a simplified version of my files :
Layout.js
export default function Layout({ children }) {
const containerRef = useRef(null);
const sectionsRef = useRef([]);
sectionsRef.current = [];
useEffect(() => {
gsap.registerPlugin(ScrollTrigger);
const scrollTimeline = gsap.timeline();
scrollTimeline.to(sectionsRef.current, {
x: () =>
`${-(
containerRef.current.scrollWidth -
document.documentElement.clientWidth
)}px`,
ease: 'none',
scrollTrigger: {
trigger: containerRef.current,
invalidateOnRefresh: true,
scrub: 0.5,
pin: true,
start: () => `top top`,
end: () =>
`+=${
containerRef.current.scrollWidth -
document.documentElement.clientWidth
}`,
},
});
}, [containerRef, sectionsRef]);
return (
<div className="slides-container" ref={containerRef}>
{children}
</div>
);
}
index.js (page)
import { graphql } from 'gatsby';
import React, { forwardRef } from 'react';
import SectionImage from '../components/sections/SectionImage';
import SectionIntro from '../components/sections/SectionIntro';
import SectionColumns from '../components/sections/SectionColumns';
const HomePage = ({ data: { home } }, sectionsRef) => {
const { sections } = home;
const addToRefs = (el) => {
if (el && !sectionsRef.current.includes(el)) {
sectionsRef.current.push(el);
}
};
return (
<>
{sections.map((section) => {
if (section.__typename === 'SanitySectionIntro') {
return (
<SectionIntro key={section.id} section={section} ref={addToRefs} />
);
}
if (section.__typename === 'SanitySectionImage') {
return (
<SectionImage key={section.id} section={section} ref={addToRefs} />
);
}
if (section.__typename === 'SanitySectionColumns') {
return (
<SectionColumns
key={section.id}
section={section}
ref={addToRefs}
/>
);
}
return '';
})}
</>
);
};
export default forwardRef(HomePage);
export const query = graphql`
query HomeQuery {
// ...
}
`;
Any clue greatly appreciated :)

vuetify + jest lists error messages although test is green

As a vue newbie I wrote a test for a component. The test is green. However, when using vuetify in the component under test (v-layout, v-flex) error messages are listed in the console output. They disappear when removing vuetify in the component (v-layout, v-flex). How can I use vuetify and still avoid those messages?
The component TestForm
<script>
import "#/assets/Styles";
import {cloneDeep} from "lodash";
import VForm from "vuetify/es5/components/VForm";
import VBtn from "vuetify/es5/components/VBtn";
import {VContainer, VContent, VFlex, VLayout, VSpacer} from "vuetify/es5/components/VGrid";
import VTextField from "vuetify/es5/components/VTextField";
import {VCard, VCardText, VCardTitle} from "vuetify/es5/components/VCard";
import TestModelData from "#/api/model/example/TestModelData";
import TestData from "#/api/model/example/TestData";
import TestStatus from "#/api/model/example/TestStatus";
import TestStatusSelect from "#/components/common/TestStatusSelect";
export default {
components: {
VBtn,
VForm,
TestModelData, TestData, TestStatus, TestStatusSelect,
VCard, VCardTitle, VCardText,
VContainer, VContent, VLayout, VFlex, VSpacer,
VTextField
},
props: {
testModelData: TestModelData
},
data() {
return {
currentTestModelData: this.testModelData,
testData: this.testData ? cloneDeep(this.testData) : new TestData()
};
},
watch: {
"testModelData.testdata": function (val) {
console.log("Testdata has changed;", val);
if (val) {
this.testData = cloneDeep(val);
} else {
this.testData = new TestData();
}
}
},
computed: {
readOnly: function () {
if (this.testData.testStatus.id !== TestStatus.FIRST.id) {
return true;
} else {
return false;
}
}
},
methods: {
onFormChange(event) {
console.log("Changed: ", event);
this.$store.dispatch({
type: "testModelData/setTestData",
testData: this.testData
});
}
}
};
</script>
<template>
<v-form ref="form">
<v-layout wrap>
<v-flex xs12 lg6>
<TestStatusSelect
ref="testDataSelect"
v-model="testData.testStatus"
#change="onFormChange($event)"/>
</v-flex>
</v-layout>
</v-form>
<!-- when comment the above and uncomment the below the error messages disappear -->
<!--<v-form ref="form">-->
<!--<TestStatusSelect-->
<!--ref="testDataSelect"-->
<!--v-model="testData.testStatus"-->
<!--#change="onFormChange($event)"/>-->
<!--</v-form>-->
</template>
The jest-test
import VueTestUtils, {createLocalVue, mount} from "#vue/test-utils";
import Vuex from 'vuex';
import Vuetify from 'vuetify';
import TestForm from "#/components/example/TestForm";
import TestModelData from "#/api/model/example/TestModelData";
VueTestUtils.config.provide['$options'] = {};
const localVue = createLocalVue();
localVue.use(Vuex);
localVue.use(Vuetify);
const TEST_MODEL_DATA = TestModelData.fromJSON({
"id": 1,
"testdata": {
"id": 1,
"name": "Foo",
"testStatus": 0,
}
});
describe('TestForm Tests', () => {
test('TestForm select testStatus', () => {
const setTestData = jest.fn();
const getters = {
"current": jest.fn().mockImplementation(() => {
return TEST_MODEL_DATA;
}),
"hasUnsavedChanges": jest.fn().mockReturnValue(false),
};
const store = new Vuex.Store({
modules: {
testModelData: {
namespaced: true,
getters: getters,
actions: {setTestData}
}
}
});
const wrapper = mount(TestForm, {
store, localVue, propsData: {
testModelData: TEST_MODEL_DATA
}
});
const first = wrapper.findAll('.v-list__tile--link').at(1);
first.trigger('click');
expect(setTestData).toHaveBeenCalled();
});
});
The component TestStatusSelect
<script>
import VSelect from "vuetify/es5/components/VSelect";
import TestStatus from "#/api/model/example/TestStatus";
export default {
components: {
VSelect
},
props: ["value", "disabled"],
data() {
return {
testStatuses: TestStatus.ALL,
testStatus: this.value ? this.value : TestStatus.FIRST
};
},
watch: {
value(val) {
if (this.testStatus.id !== val.id) {
console.log('VALUE');
this.testStatus = val;
}
},
testStatus(val, oldVal) {
if (val.id !== oldVal.id) {
this.$emit("input", val);
this.$emit("change", val);
}
}
}
};
</script>
<template>
<v-select
ref="testStatusSelect"
:disabled="disabled"
label="Result"
:items="testStatuses"
item-text="name"
item-value="id"
v-model="testStatus"
return-object>
</v-select>
</template>
The class TestModelData
import TestData from "#/api/model/example/TestData";
class TestModelData {
constructor() {
this.id = null;
this.testData = null;
}
fromJSON(json) {
this.id = json.id;
this.testData = TestData.fromJSON(json.testData);
}
toJSON() {
const o = {
id: this.id,
};
if (this.testData) {
a.testData = this.testData.toJSON();
}
return o;
}
static fromJSON(json) {
if (!json) {
return null;
} else {
const a = new TestModelData();
a.fromJSON(json);
return a;
}
}
}
export default TestModelData;
The class TestData
import TestStatus from "#/api/model/example/TestStatus";
class TestData {
constructor() {
this.id = null;
this.name = null;
this.testStatus = TestStatus.FIRST;
}
fromJSON(json) {
this.id = json.id;
this.name = json.name;
this.testStatus = json.testStatus !== null ? TestStatus.fromJSON(json.testStatus) : null;
}
toJSON() {
const o = {
id: this.id,
};
o.name = this.name;
o.testStatus = this.testStatus ? this.testStatus.toJSON() : null;
return o;
}
static fromJSON(json) {
if (!json) {
return null;
} else {
const a = new TestData();
a.fromJSON(json);
return a;
}
}
}
export default TestData;
The class TestStatus
import PropTypes from "prop-types";
import Definition from "../Definition";
class TestStatus extends Definition {
constructor(id, name) {
super();
this.id = id;
this.name = name;
}
static FIRST = new TestStatus(0, "first");
static SECOND = new TestStatus(1, "second");
static ALL = [
TestStatus.FIRST,
TestStatus.SECOND
];
toJSON() {
return this.id;
}
static fromJSON(json) {
if (json === TestStatus.FIRST.id) {
return TestStatus.FIRST;
}
else if (json === TestStatus.SECOND.id) {
return TestStatus.SECOND;
}
console.error("TestStatus unknown", json);
throw new Error(`TestStatus ${json} unknown`, json);
}
}
TestStatus.prototype.PROPTYPES = {
id: PropTypes.number,
name: PropTypes.string,
};
export default TestStatus;
The console output
console.error node_modules/#vue/test-utils/dist/vue-test-utils.js:15
[vue-test-utils]: an extended child component <VBtn> has been modified to ensure it has the correct instance properties. This means it is not possible to find the component with a component selector. To find the component, you must stub it manually using the stubs mounting option.
console.error node_modules/#vue/test-utils/dist/vue-test-utils.js:15
[vue-test-utils]: an extended child component <VCard> has been modified to ensure it has the correct instance properties. This means it is not possible to find the component with a component selector. To find the component, you must stub it manually using the stubs mounting option.
console.error node_modules/#vue/test-utils/dist/vue-test-utils.js:15
[vue-test-utils]: an extended child component <VCardTitle> has been modified to ensure it has the correct instance properties. This means it is not possible to find the component with a component selector. To find the component, you must stub it manually using the stubs mounting option.
console.error node_modules/#vue/test-utils/dist/vue-test-utils.js:15
[vue-test-utils]: an extended child component <VCardText> has been modified to ensure it has the correct instance properties. This means it is not possible to find the component with a component selector. To find the component, you must stub it manually using the stubs mounting option.
console.warn node_modules/vuetify/es5/util/console.js:32
[Vuetify] Unable to locate target [data-app]
found in
---> <VMenu>
<VSelect>
<TestStatusSelect>
<VForm>
<VCard>
<Anonymous>
<Root>
console.error node_modules/vue/dist/vue.common.js:593
[Vue warn]: $listeners is readonly.
found in
---> <VSelect>
<TestStatusSelect>
<VForm>
<VCard>
<Anonymous>
<Root>
console.log src/components/example/TestForm.vue:800
Changed: TestStatus {
_clazz: [Getter/Setter],
id: [Getter/Setter],
name: [Getter/Setter] }
console.error node_modules/vue/dist/vue.common.js:593
[Vue warn]: $listeners is readonly.
found in
---> <VSelect>
<TestStatusSelect>
<VForm>
<VCard>
<Anonymous>
<Root>
console.error node_modules/vue/dist/vue.common.js:593
[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "value"
found in
---> <VSelect>
<TestStatusSelect>
<VForm>
<VCard>
<Anonymous>
<Root>
console.error node_modules/vue/dist/vue.common.js:593
[Vue warn]: $listeners is readonly.
found in
---> <VSelect>
<TestStatusSelect>
<VForm>
<VCard>
<Anonymous>
<Root>
There are a few solutions / work arounds in this thread.
This is the one that worked for me, I added it at the top of my test body:
document.body.setAttribute('data-app', true)
find the button by id and triggering a click may occur the warning to resolve this issue consider the below code
let element_forgetBtn = wrapper.find("#forgotPasswordBtn");
> let app = document.createElement("div");
> app.setAttribute("data-app", true);
> document.body.append(app);
element_forgetBtn.trigger("click");
complete code is below
let element_forgetBtn = wrapper.find("#forgotPasswordBtn");
let app = document.createElement("div");
app.setAttribute("data-app", true);
document.body.append(app);
element_forgetBtn.trigger("click");

Resources