Vue3 testing ElementPlus controls with vitest - vuejs3

I am running Vue3 with vite and can't write any tests for components that use the ElementPlus library. Something else needs to be injected apparently but I don't know how to do that.
I have the following dateControl.test.js:
import { describe, expect, test } from 'vitest';
import { ref } from 'vue';
import DateCtrl from '#/components/DateCtrl.vue';
import { mount } from "#vue/test-utils";
import ElementPlus from "element-plus";
describe("DateCtrl.vue", () => {
const messages = {
"en-US" : {
strings: {
placeholder: 'a',
label: 'b'
}
}
};
const locale = "en-US";
const data = ref ({
date: ''
});
test ("Arrange DateCtrl", async () => {
const component = mount(DateCtrl, {
props: {
vModel: data.value.date,
modelValue: data.value.date,
labelLoc: "label",
className: "w1x5",
placeholderLoc: "date"
},
global: {
plugins: [ElementPlus],
mocks: {
$t: (msg) => {
const params = msg.split('.');
return messages[locale][params[0]][params[1]];
}
}
}
});
//fails on previous lines.
expect(typeof component !== "undefined", "component created").toBeTruthy();
let h3Text = component.findAll('h3')[0].element.innerHTML;
expect(component.findAll('.form').length === 1, "form element rendered").toBeTruthy();
expect(h3Text === "d", "locale strings correct").toBeTruthy();
});
});
It doesn't even get to the "expect" tests, fails with message:
Error: Cannot find module 'C:\source\mySite\node_modules\dayjs\plugin\customParseFormat'
imported from
C:\source\mySite\node_modules\element-plus\es\components\date-picker\src\date-picker.mjs
Did you mean to import dayjs/plugin/customParseFormat.js?

This bit seems to indicate that node expects you to use .js extension and element is not doing that.
Error: Cannot find module 'C:\source\mySite\node_modules\dayjs\plugin\customParseFormat'
imported from
C:\source\mySite\node_modules\element-plus\es\components\date-picker\src\date-picker.mjs
Did you mean to import dayjs/plugin/customParseFormat.js?
I'm guessing this is because you may be running an older node version. Element requires at least node v16.

I have this problem too.
It seems that this problem is already solved in this pull request - https://github.com/element-plus/element-plus/pull/6811

Related

nextjs: TypeError: createServer is not a function

I am trying to follow this tutorial:
I am stuck at step 3, which is where the server is defined as follows:
import { createServer } from "#graphql-yoga/node";
import { join } from "path";
import { readFileSync } from "fs";
const typeDefs = readFileSync(join(process.cwd(), "schema.graphql"), {
encoding: "utf-8",
});
const resolvers = {
Query: {
cart: (_, { id }) => {
return {
id,
totalItems: 0,
};
},
},
};
const server = createServer({
cors: false,
endpoint: "/api",
logging: {
prettyLog: false,
},
schema: {
typeDefs,
resolvers,
},
});
export default server;
When I try to use that definition and start the local host, I get an error that says:
TypeError: (0 ,
graphql_yoga_node__WEBPACK_IMPORTED_MODULE_0_.createServer) is not a function at eval
Can anyone see if this tutorial is now out of date. I can see that I am using next v 13.1.1 and the tutorial uses v12. I've been having an awful time trying to find an explanation of how to use these packages, in their current formats. Is this one now out of date?
Can anyone see how to define a server for next v13?
There are some change between graph-yoga v2 and v3, you can look this tutorial to solve it.
For others that might be stuck, this might be a way to define the schema using graphql-yoga (now instead of graphql-yoga/node)
import { createSchema, createYoga } from 'graphql-yoga'
import { createServer } from 'node:http'
import { join } from "path";
import { readFileSync } from "fs";
const typeDefs = readFileSync(join(process.cwd(), "schema.graphql"), {
encoding: "utf-8",
});
const resolvers = {
Query: {
cart: (_, { id }) => {
return {
id,
totalItems: 0,
};
},
},
};
const yoga = createYoga({
cors: false,
endpoint: "/api",
logging: {
prettyLog: false,
},
schema: createSchema({
typeDefs,
resolvers,
}),
});
const server = createServer(yoga);
server.listen(3000, () => {
console.info('Server is running on http://localhost:3000/graphql')
});
export default server;

trpc v10 - Error: Query data cannot be undefined

New to trpc. Trying to get basic query functionality but it's not working. Not sure what I'm missing. In v9 it used createReactQueryHooks(), but it seems in v10 you only need to use createTRPCNext() if I'm not mistaken inside util/trpc.tsx.
Error:
next-dev.js:32 Error: Query data cannot be undefined - affected query key: ["greeting"]
at Object.onSuccess (query.mjs:320:19)
at resolve (retryer.mjs:64:50)
// utils/trpc.ts
export const trpc = createTRPCNext<AppRouter, SSRContext>({
config({ ctx }) {
return {
transformer: superjson, // optional - adds superjson serialization
links: [
httpBatchLink({
/**
* If you want to use SSR, you need to use the server's full URL
* #link https://trpc.io/docs/ssr
**/
url: `${getBaseUrl()}/api/trpc`,
}),
],
/**
* #link https://react-query-v3.tanstack.com/reference/QueryClient
**/
// queryClientConfig: { defaultOptions: { queries: { staleTime: 60 } } },
headers() {
if (ctx?.req) {
// To use SSR properly, you need to forward the client's headers to the server
// This is so you can pass through things like cookies when we're server-side rendering
// If you're using Node 18, omit the "connection" header
const {
// eslint-disable-next-line #typescript-eslint/no-unused-vars
connection: _connection,
...headers
} = ctx.req.headers;
return {
...headers,
// Optional: inform server that it's an SSR request
"x-ssr": "1",
};
}
return {};
},
};
},
ssr: true,
});
// server/router/_app.ts
import { t } from '#/server/trpc';
import { userRouter } from '#/server/router/user';
import { postRouter } from '#/server/router/posts';
import { authRouter } from './authy';
export const appRouter = t.router({
user: userRouter,
post: postRouter,
authy: authRouter,
greeting: t.procedure.query(() => 'hello tRPC v10!'),
});
export type AppRouter = typeof appRouter;
// server/router/authy.ts
import { t } from "#/server/trpc";
import * as trpc from "#trpc/server";
import { z } from "zod";
export const authRouter = t.router({
hello: t.procedure
// using zod schema to validate and infer input values
.input(
z.object({
text: z.string().nullish(),
})
.nullish().optional()
)
.query(({ input }) => {
return {
greeting: `hello ${input?.text ?? "world"}`,
};
}),
});
export type AuthRouter = typeof authRouter;
None of the routes work. They all show a similar error.
// pages/test.tsx
import React from "react";
import { NextPage } from "next";
import { trpc } from "#/utils/trpc";
const TestPage: NextPage = () => {
const helloNoArgs = trpc.authy.hello.useQuery();
const helloWithArgs = trpc.authy.hello.useQuery({ text: "client" });
const greeting = trpc.greeting.useQuery();
return (
<div>
<h1>Hello World Example</h1>
<ul>
<li>
helloNoArgs ({helloNoArgs.status}):{" "}
<pre>{JSON.stringify(helloNoArgs.data, null, 2)}</pre>
</li>
<li>
helloWithArgs ({helloWithArgs.status}):{" "}
<pre>{JSON.stringify(helloWithArgs.data, null, 2)}</pre>
</li>
<li>
greeting ({greeting.status}):{" "}
<pre>{JSON.stringify(greeting.data, null, 2)}</pre>
</li>
</ul>
</div>
);
};
export default TestPage;
It seems you are using superjson. You need to add superjson transformer at initTRPC.
routers/router/_app.ts
import { initTRPC } from '#trpc/server';
import superjson from 'superjson';
export const t = initTRPC.create({
transformer: superjson,
});
more detailed instruction can be found here: TRPC v10
Omgosh... it was because I was using "^10.0.0-proxy-beta.7" and not "^10.0.0-proxy-beta.8"
Edit: Somehow I had another error and encountered my own question again 22 days later and solved it again. In general, when using trpc it seems updating to all the #next packages is best as it seems to be somewhat easy to have packages not talking to each other as they improve.
https://trpc.io/docs/v10/quickstart#installation-snippets
On my side I was using a mocked trpc server that was not using superjson (whereas the real one was). I just used superjson.serialize(...) before adding the JSON body to my response (in my server mock), then it worked :)

Next.js hydration error using Keycloak SSR package

I am using #react-keycloak/ssr with latest next.js, just started so project as clean as possible, all I really have are installed dependencies and _app.tsx with index.tsx from examples.
_app.tsx is identical copy (except url to keycloak) of official github example and index.tsx is next:
import { useKeycloak } from '#react-keycloak/ssr'
import {KeycloakInstance, KeycloakTokenParsed} from 'keycloak-js'
type ParsedToken = KeycloakTokenParsed & {
email?: string
username?: string
}
export default function Index() {
const { keycloak } = useKeycloak<KeycloakInstance>()
const parsedToken: ParsedToken | undefined = keycloak?.tokenParsed
const state = keycloak?.authenticated ? <span>{parsedToken?.username}</span> : <span>'Undefined'</span>;
function handleLoginButtonClick() {
if (keycloak) {
window.location.href = keycloak.createLoginUrl()
}
}
return (
<div>
{state}
<button className="btn btn-blue" onClick={() => handleLoginButtonClick()}>Login</button>
</div>
)
}
And my problem is that after a login I am getting errors
Warning: Text content did not match. Server: "" Client: "'Undefined'"
at span
at div
at Index (webpack-internal:///./pages/index.tsx:18:84)
I've tried to implement state change using useEffect but then keycloak?.authenticated is always false,
let [state] = useState('No user');
useEffect(() => {
state = keycloak?.authenticated ? 'User' : 'No user';
}, []);
then I tried to use getServerSideProps, but then I get an error that useKeycloak hook can be used inside a function only.
What else can I try?
p.s. Short gif/video of what is happening https://imgur.com/a/c2q6ftU
Found a solution by tweaking useEffect slightly:
const [username, setUsername] = useState('unknown')
useEffect(() => {
if (keycloak?.authenticated) {
setUsername(parsedToken?.email)
}
}, [keycloak?.authenticated])

Is it possible to get i18n translation source file from firebase?

Is it possible to modify vue-i18n so translation single JSON file with 2 different language inside and which come form Firebase will render text dynamically to vue template
I used mounted function with axios to get data form firebase. But I have no clue how i18n should treat this as a source file for a translation.
Basically I put my two translation source files from locales folder to the one United.json and I uploaded this to firebase, now I want to load this back to my app form there (firebase) but I see no solution there how to set locale so that it will render and translate all the {{ $t(example.locale) }} and I should be able to be bind it as this v-bind:src="$t('products.'+ index +'.options.'+ i +'.image')"
//main.js
import Vue from 'vue'
import i18n from './i18n'
import axios from 'axios'
Vue.config.productionTip = false
router.beforeEach((to, from, next) => {
let language = to.params.lang;
if (!language) {
language = 'ee'
}
i18n.locale = language
next()
});
new Vue({
router,
i18n,
render: h => h(App),
data() {
return{
localekk : ''
}
}
,
methods: {
setLocale(lang) {
Vue.$i18n.locale = lang;
}
},
mounted() {
axios.get('https://example.firebaseio.com/locales.json')
.then(response => {
this.locale = response.data;
console.log(response)
})
.catch(error => console.log(error))
}
}).$mount('#app')
//i18n.js
import Vue from 'vue'
import VueI18n from 'vue-i18n'
Vue.use(VueI18n)
function loadLocaleMessages () {
const locales = require.context('./locales', true, /[A-Za-z0-9-_,\s]+\.json$/i) // may by to change './locales' but again - how?
const messages = {}
locales.keys().forEach(key => {
const matched = key.match(/([A-Za-z0-9-_]+)\./i)
if (matched && matched.length > 1) {
const locale = matched[1]
messages[locale] = locales(key)
}
})
return messages
}
export default new VueI18n({
locale: process.env.VUE_APP_I18N_LOCALE || 'ee',
fallbackLocale: process.env.VUE_APP_I18N_FALLBACK_LOCALE || 'ee',
messages: loadLocaleMessages(),
silentTranslationWarn: true,
})

jest for testing describe is not a function

I have made an app using react and redux, I have some components plus their containers and also an action and a reducer.
I am writing a test for one of my containers using enzyme, chai and jest,
when I try to run my test it gives the following error:
Test suite failed to run
TypeError: jest_1.describe is not a function
here is my test file:
import * as React from "react";
import { shallow, mount, render } from 'enzyme';
import * as Sinon from "sinon";
import MinPriceContainer from "../../src/containers/SearchForm/containers/MinPriceContainer";
import MaxPriceContainer from "../../src/containers/SearchForm/containers/MaxPriceContainer";
import { expect } from "chai";
import { it, before, describe } from 'jest';
describe('<MinValueInput />', () => {
let minValueInput;
beforeEach(() => {
minValueInput = shallow(<MinPriceContainer />);
})
// it('renders component correctly', () => {
// expect(tabs.find('.MinPriceComponent').exists()).toBe(true);
// });
it('cannot have a non numeric value', () => {
minValueInput = shallow(<MinPriceContainer minimumPriceSelected="i am a string not a number" />);
expect(minValueInput.find('.error').text()).equal("You cannot use a non numeric value");
});
it('cannot have a value less thn zero', () => {
minValueInput = shallow(<MinPriceContainer minimumPriceSelected={-20} />);
expect(minValueInput.find('.error').text()).equal("value cannot be less than zero");
});
it('it can not have a value greater than maxValue', () => {
minValueInput = shallow(<MinPriceContainer minimumPriceSelected={99} maximumPriceSelected={80}/>);
expect(minValueInput.find('.error').text()).equal("value cannot be greater than price");
});
});
how can I fix this, is this related to my importS?
is the test written correctly?
the component that I am testing has a number value called minPrice and it can not be negative and also it should not be more than another component that is called maxPrice, also it should only accepts numbers!
I take it you're using ts-jest?
replace
import { it, before, describe } from 'jest';
with
import 'jest';

Resources