How to mock a imported function in vue component? - jestjs

I'm testing my vue component, and I want to mock a function imported in component:
// backtop.vue
<template>
<transition name="ten-fade-in">
<div
v-if="_finishVisible"
class="ten-backtop"
:style="{
right: _offsetRight,
bottom: _offsetBottom
}"
#click="handleClick"
>
<!-- #slot 回到顶部内容 -->
<slot>
<ten-button
class="ten-backtop-button"
theme="default"
icon="backtop"
round
icon-only
/>
</slot>
</div>
</transition>
</template>
<script>
import throttle from 'lodash/throttle';
import TenButton from '../button';
import DomHelper from '#/components/scripts/utils/dom-helper';
const { scrollTo, getScroll } = DomHelper;
And all I want is to mock the "scrollTo" function.
// backtop.test.js
import Vue from "vue";
import { mount } from "#vue/test-utils";
jest.mock('#/components/scripts/utils/dom-helper', () => ({
scrollTo: jest.fn()
}));
import DomHelper from '#/components/scripts/utils/dom-helper';
const { scrollTo } = DomHelper;
import Backtop from '../backtop.vue';
But when I run the test, jest still uses the original real module in backtop.vue, the mock module only worked in backtop.test.js but didn't work in backtop.vue, any solution please?

Related

What is console.error in react testing and is it okay to ignore?

I am on the way to learning Jest and React Testing Library.
When I run the test below, it is 'passed' but I see the console.error message.
[sectionIntro.spec.js]
import React from "react";
import { fireEvent, render, screen } from "#testing-library/react";
import SectionIntro from "../../components/home/SectionIntro.jsx";
import { CV_URL } from "../../lib/socials";
describe("SectionIntroComponent", () => {
it("Should open the CV link when CV button is clicked", () => {
render(<SectionIntro />);
const cv_link = screen.getByText(/Check My CV/i);
expect(cv_link.href).toBe(CV_URL);
});
});
// Also a mock file is used for an image file.
[SectionIntro.jsx]
import * as React from "react";
import Image from "next/image";
import profilePic from "../../public/me.png";
import styles from "../../styles/SectionIntro.module.css";
import { CV_URL } from "../../lib/socials";
const SectionIntro = () => {
return (
<>
<div>
<div>
<Image
className="rounded-full"
src={profilePic}
alt="The author of the website"
objectFit="cover"
sizes="30vw"
/>
</div>
</div>
<div>
<button
className={`${styles.btnCV}`}
>
<a
href={CV_URL}
aria-label="CV"
target="_blank"
rel="noopener noreferrer"
>
Check My CV
</a>
</button>
</div>
</>
);
};
export default SectionIntro;
[mocks/mockFile.js]
export default "";
My question is if the test result is passed why the console.error is shown?
Would it be okay to ignore console.error?
If it is not a good idea to hide the console, why is it so?
Thanks alot in advance!

reaching data inside an object while using map

I'm sorry in advance for my ignorance, But its been a while since I coded, and I need a little help with this basic thing, Im trying to reach name, and display it on screen when I click a button, but i just can't figure it out, can u help me and explain what you did so I can know for the next time? looked manuals and articles about how to do it but you guys are just simply better.
my code:
functional (pokeAPI.ts):
import React from "react";
import axios from 'axios'
export const getPokemon=()=>{
axios.get("https://pokeapi.co/api/v2/pokemon?limit=151").then((response)=>{
response.data.results.map((cont : string,index : number) => console.log(
cont
));
})
}
app.tsx:
import './App.css';
import React from 'react';
import {getPokemon} from './func/pokeAPI';
function App() {
return (
<div>
<button onClick={getPokemon}>Cli</button>
</div>
);
}
export default App;
Here you go! Since you're using typescript, I created a PokemonData interface as well.
import React from 'react'
import axios from 'axios'
import "./styles.css";
interface PokemonData {
name: string
url: string
}
export default function App() {
const [pokemons, setPokemons] = React.useState<null|PokemonData[]>(null)
const onClick = async () => {
axios.get("https://pokeapi.co/api/v2/pokemon?limit=151").then((response)=>{
console.log(response.data.results)
setPokemons(response.data.results)
})
}
return (
<div className="App">
<button onClick={onClick}>Get pokemon</button>
{pokemons?.map((pokemon) => (
<div key={pokemon.name}>
<p>{pokemon.name}</p>
<p>{pokemon.url}</p>
</div>
))}
</div>
);
}
I also wrote a Codesandbox here so you can check it out
Edit: Another version of the return statement if optional chaining isn't supported on your project's version
return (
<div className="App">
<button onClick={onClick}>Get pokemon</button>
{pokemons && pokemons.map((pokemon) => (
<div key={pokemon.name}>
<p>{pokemon.name}</p>
<p>{pokemon.url}</p>
</div>
))}
</div>
);
}

With styled components how to pass theme color from Global Style to React Icons Context Provider?

Looking for a way to pass color from theme to React Icons. Theme is working correctly and I'm able to pass colors to my styled components. Here is the breakdown:
index.js:
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
// Theme
import { ThemeProvider } from 'styled-components'
import { GlobalStyles } from './theme/GlobalStyles'
import Theme from './theme/theme'
ReactDOM.render(
<ThemeProvider theme={Theme}>
<GlobalStyles />
<App />
</ThemeProvider>,
document.getElementById('root'),
)
app.js (stripped down):
<IconContext.Provider value={{ color: `${({ theme }) => theme.colors.white}` }}>
<FaTimes />
<FaBars />
</IconContext.Provider>
the equivalent of:
<IconContext.Provider value={{ color: `#fff` }}>
<FaTimes />
<FaBars />
</IconContext.Provider>
does work and I did try:
NavElements.js:
import { IconContext } from 'react-icons/lib'
export const NavProvider = styled(<IconContext.Provider>{children}</IconContext.Provider>)`
color: ${({ theme }) => theme.colors.color2};
`
app.js:
// <IconContext.Provider value={{ color: `#fff` }}>
<NavProvider>
// Further code
</NavProvider>
// </IconContext.Provider>
but I get a children error. Attempt came from reading Q&A Styled-components and react-icons <IconContext.Provider> component
Other Q&As I found with no luck:
How to Style React-Icons
react-icons apply a linear gradient
With a theme color in Styled Components how can I pass that color to React Icons Provider?
I haven't worked with react-icon but this might help
Take a look at getting the theme without styled components - there is also a hook
Your example
export const NavProvider = styled(<IconContext.Provider>{children}</IconContext.Provider>)`
color: ${({ theme }) => theme.colors.color2};
`
work because styled expects a HTML element or a React component
Your NavProvider could be something like (haven't tried this code but it should work)
import { useContext } from 'react';
import { ThemeContext } from 'styled-components';
export const NavProvider = ({children}) => {
const themeContext = useContext(ThemeContext);
return (
<IconContext.Provider value={{ color: themeContext.colors.color2 }}>
{children}
</IconContext.Provider>
);
};

Monitoring multiple server stats in React JS

I have multiple pods running on my Kubernetes cluster and I have a "core app" built with react from which I want to get CPU & Memory usage stats.
Right now I am testing using a very simple setup where I have a local node app using socket.io to stream the time (based on this tutorial)
However, with one component which looks like the following, I am able to get real time updates from the server.
import React, { useState, useEffect } from "react";
import socketIOClient from "socket.io-client";
import {StatsCPUWrapper} from './statsCPU.style'
const ENDPOINT = process.env.STATS_ENDPOINT || "http://127.0.0.1:4001";
function StatsCPUComp() {
const [cpustats, setCPUstats] = useState("");
useEffect(() => {
const socket = socketIOClient(ENDPOINT);
socket.on("FromAPI", data => {
setCPUstats(data);
});
// Clean up the effect
return () => socket.disconnect();
}, []);
return (
<StatsCPUWrapper>
<p>
It's <time dateTime={cpustats}>{cpustats}</time>
</p>
</StatsCPUWrapper>
);
}
export default StatsCPUComp;
What I am now trying to do is have 3 or more of those components (depends on the list I get from my backend) to "subscribe" to multiple servers at the same time.
Here's my "projects list" component which gets the stats from the initial state and renders all the details:
import React from 'react'
import {useSelector, useDispatch} from 'react-redux'
import {Link} from 'react-router-dom'
import PropTypes from 'prop-types'
import {create, remove} from '../../features/projects/projectSlice'
import {ProjectWrapper} from './project.style'
import StatsCPUComp from './stats/statsCPU'
export function ProjectComp() {
const dispatch = useDispatch()
const projects = useSelector((state) => state.projects)
const handleSubmit = (e) => {
e.preventDefault()
}
const handleAction = (e) => {
e.preventDefault()
}
return (
<ProjectWrapper>
<div className="projects">
<div className="row">
{projects.map((projects) => (
<div className="col-12">
<div class="card project-card">
<div className="card-body">
<div className="row">
<div className="col-4 project-text">
<h5 class="card-title">
{' '}
<Link to={`/projects/` + projects.id}>{projects.name}</Link>
</h5>
<p class="card-text">Owner: {projects.owner}</p>
<p class="card-text">{projects.email}</p>
</div>
<div className="col-4 projects-stats">
<StatsCPUComp />
</div>
<div className="col-4 projects-stats"></div>
<div className="col-4 projects-stats"></div>
</div>
</div>
</div>
<br></br>
</div>
))}
</div>
</div>
</ProjectWrapper>
)
}
Right now the "time" from the stats component is being added on my last project component (makes sense since I did not implement any approach yet to map that too).
Any ideas on how I can have a different stats component for each of my "projects" where each one connects to a provided endpoint ? (I can pass all of the endpoints as env variables)
Any help would be highly appreciated.
So here's the implementation I did to make it work. (Not sure if it's ideal so please feel free to make any suggestions)
I added "endpoint" to state.projects which holds the data I get from my backend.
Then in my "projects list" component mentioned shown in the question, I pass projects (from state.projects) as props
<StatsCPUComp props={projects}/>
I then destructure it and pass it to my useEffect() in the stats component as follows:
import React, {useState, useEffect} from 'react'
import socketIOClient from 'socket.io-client'
import {StatsCPUWrapper} from './statsCPU.style'
import {useSelector, useDispatch} from 'react-redux'
let ENDPOINTS = []
let PROJECTS = []
function StatsCPUComp(...props) {
const [cpustats, setCPUstats] = useState('')
let endpoints = {...props}
let endpoints_2 = {...endpoints[0]}
useEffect(() => {
let socketlist = []
console.log(endpoints[0].props.endpoint)
const socket = socketIOClient(endpoints[0].props.endpoint);
socket.on("FromAPI", data => {
setCPUstats(data);
});
return () => socket.disconnect();
}, [cpustats])
return (
<>
<StatsCPUWrapper>
<p>
It's <time dateTime={cpustats}>{cpustats}</time>
</p>
</StatsCPUWrapper>
</>
)
}
export default StatsCPUComp
It seems to be working fine, however please do provide any suggestions since I might not be following an optimal approach (Performance and scalability wise)

React is not defined in simple React component ( Universal )

I'm using 15.0.1 and using React to create Universal app
I was getting React is not defined in the following component
import {Component} from "react";
export default class HeroSearchView extends Component{
render() {
return (
<div className='row'>
hello
</div>
);
}
}
The following code call that React component
import React from "react";
import { connect } from 'react-redux'
import Coupon from '../../common/components/Coupon'
import { actions as miscActions } from '../../redux/modules/misc'
import HeroSearchView from './components/HeroSearchView'
const mapStateToProps = (state) => ({
misc:state.misc
})
export class HomeView extends React.Component{
render() {
return (
<div>
<HeroSearchView />
<Coupon {...this.props} />
</div>
);
}
}
export default connect(mapStateToProps, Object.assign({}, miscActions))(HomeView)
I'm kind of scratching my head now what the following message means ...
ReferenceError: React is not defined
at HeroSearchView.render (HeroSearchView.jsx:8:13)
at [object Object].ReactCompositeComponentMixin._renderValidatedComponentWithoutOwnerOrContext (/Users/roy/development/org/pl-core/node_modules/react/lib/ReactCompositeComponent.js:679:34)
at [object Object].ReactCompositeComponentMixin._renderValidatedComponent (/Users/roy/development/org/pl-core/node_modules/react/lib/ReactCompositeComponent.js:699:32)
at [object Object].wrapper [as _renderValidatedComponent] (/Users/roy/development/org/pl-core/node_modules/react/lib/ReactPerf.js:66:21)
at [object Object].ReactCompositeComponentMixin.performInitialMount (/Users/roy/development/org/pl-core/node_modules/react/lib/ReactCompositeComponent.js:284:30)
at [object Object].ReactCompositeComponentMixin.mountComponent (/Users/roy/development/org/pl-core/node_modules/react/lib/ReactCompositeComponent.js:237:21)
at [object Object].wrapper [as mountComponent] (/Users/roy/development/org/pl-core/node_modules/react/lib/ReactPerf.js:66:21)
at Object.ReactReconciler.mountComponent (/Users/roy/development/org/pl-core/node_modules/react/lib/ReactReconciler.js:39:35)
at ReactDOMComponent.ReactMultiChild.Mixin.mountChildren (/Users/roy/development/org/pl-core/node_modules/react/lib/ReactMultiChild.js:203:44)
at ReactDOMComponent.Mixin._createContentMarkup (/Users/roy/development/org/pl-core/node_modules/react/lib/ReactDOMComponent.js:589:32)
[ Note ] : If I remove <HomeSearchView /> from my example code, it works fine ...
Any tips will be appreciated ...
You need to use
import React from "react"
and
export default class HeroSearchView extends React.Component
This is because JSX convert your file to actual JS that calls React.createElement, and because you only imported Component from react, it couldn't find references to React
You can do something like this to keep your code tidy.
import React, {Component} from "react";
export default class HeroSearchView extends Component {
render() {
return (
<div className='row'>
hello
</div>
);
}
}
import React from "react";
export default class HeroSearchView extends React.Component{
render() {
return (
<div className='row'>
hello
</div>
);
}
}
Change to this and it will work.
If you are using Rails, then possible cause of error is that you added
//= require react
//= require react_ujs
//= require components
into your app/assets/javascripts/application.js

Resources