How to test React dynamic style prop? - css

Am teaching myself React and am starting on testing. Using the recommended stuff from the docs... create-react-app, jest, testing-library/react. I have a component that renders a dynamic style, something like this
const ScalingDiv = (props) => (
<StyledDiv size={props.size || 42}>
<OtherEl>
{props.text}
</OtherEl>
</StyledDiv>
);
I would like to verify that my logic in there is working correctly (that 42 is used as a fallback size). I cannot find any examples or docs of this. I had hoped that something like this would work-
test('check fallback size', async () => {
const {container} = render(<ScalingDiv/>);
expect(container.firstChild).toHaveAttribute('size', 42);
});
But I haven't found any combination of matchers and queries that returns ANY attributes. Then I tried to just check the style directly using jest-dom, but toHaveStyle('this_isnt_valid_css: 199') passes- I couldn't stick anything in there to get it to fail. So... what is the right way to do this?

It's not attribute but prop. So we can refer to prop() and props() methods like
expect(container.firstChild.prop('size')).toEqual(42);
or
expect(container.firstChild.props()).toEqual({
size: 42
});

Related

Importing CSS helper function that uses 'document' in NextJS

I am using styled-components. I'd like to import a function that helps create fluid styles. My function uses the following:
const root = document.querySelector('html');
const pixelsPerRem = Number(getComputedStyle(root).fontSize.slice(0, -2));
When I import my function using
`const clampBuilder = dynamic(() => import('utils/clampBuilder'), {
ssr: false,
});`
I see clampBuilder is not a function. I understand that since NextJS is SSR, there is no document. I am wondering how I could import my helper function or somehow use it to calculate what I need.
Function gist: https://gist.github.com/RockinRonE/b163549f684c1b4841941a6054888602
Above error says that your clampBuilder is not a function and it doesnt seems to be any issue with SSR or with document.
can you try updating dynamic import as following:
const clampBuilder = dynamic(import('utils/clampBuilder'), { ssr: false })
I ended up removing the two lines shown above from the function and set pixelsPerRem to 16 since that's the default for most browsers. It may not be perfect, but it is good enough!

Flags inside a React Bootstrap select option renders as [object, object]

I want to display Flags icons inside a React Bootstrap selection Option. I have tried both CSS based and React based libraries to do so and in each case I get only [object object]
I have tried with the https://github.com/lipis/flag-icon-css CSS library
<Form.Control as="select">
<option><span className="flag-icon flag-icon-gr"></span></option>
</Form.Control>
Which gives me a warning and the same [Object object]
Warning: Only strings and numbers are supported as <option> children.
I have also attempted with the React wrapper for the same library https://www.npmjs.com/package/react-flag-icon-css
<Form.Control as="select">
<option><FlagIcon className="countryIcon" code="us" size="lg"/></option>
</Form.Control>
Which does not generate a warning but no results either
Does anyone know how I can get something else than string or number in the Option, or another way to include an icon ?
Option HTML tag accepts text only, it can't accept any other HTML, it will strip it. You can check this React issue [bug][16.5.0] option returns [object Object] instead of string and read the comment by Dan Abramov:
I don't think it was strictly a regression. This is kind of a thorny
area. It was never intentionally supported. It accidentally worked on
initial mount but then crashed on updates (#13261). Fixing the crash
was more important, so we fixed it to be treated as text content
(which it should be). Unfortunately this means putting custom
components in the middle is not supported. That's consistent with how
textarea and similar elements work.
I think it's better to show invalid output and warn about something
that breaks on updates, than to let people use it only to discover it
crashes in production. But I can see arguments for why this should be
supported when the custom component returns a string. Unfortunately I
don't know how to fix it in a way that would both solve the update
crashes and support text-only content. I think for now it's reasonable
to say putting custom components into doesn't really work
(and never quite worked correctly), and ask you to manually provide a
string to it.
Alternatively, you can use Bootstrap Dropdowns to create a dropdown button with a list of countries using the code below:
App.js:
...
import Dropdown from 'react-bootstrap/Dropdown';
import FlagIcon from './FlagIcon.js'
function App() {
const [countries] = useState([
{ code: 'gr', title: 'Greece'},
{ code: 'gb', title: 'United Kingdom'},
{ code: 'us', title: 'United States'}
]);
const [toggleContents, setToggleContents] = useState("Select a country");
const [selectedCountry, setSelectedCountry] = useState();
return (
<div className="App">
<Form>
<Dropdown
onSelect={eventKey => {
const { code, title } = countries.find(({ code }) => eventKey === code);
setSelectedCountry(eventKey);
setToggleContents(<><FlagIcon code={code}/> {title}</>);
}}
>
<Dropdown.Toggle variant="secondary" id="dropdown-flags" className="text-left" style={{ width: 300 }}>
{toggleContents}
</Dropdown.Toggle>
<Dropdown.Menu>
{countries.map(({ code, title }) => (
<Dropdown.Item key={code} eventKey={code}><FlagIcon code={code}/> {title}</Dropdown.Item>
))}
</Dropdown.Menu>
</Dropdown>
</Form>
</div>
);
}
FlagIcon.js:
import React from 'react';
import FlagIconFactory from 'react-flag-icon-css';
// const FlagIcon = FlagIconFactory(React);
// If you are not using css modules, write the following:
const FlagIcon = FlagIconFactory(React, { useCssModules: false })
export default FlagIcon;
You'll get a dropdown button like this:
You can also check this working Stackblitz: https://stackblitz.com/edit/react-bootstrap-flags-dropdown-menu
Are you closing the tag
<Form.Control as="select">
[object Object] is displayed e.g when you are concatenating a string with an object, for example:
console.log(""+{})

How to use react-jss within react class Components?

In react-jss documentation, the authors have written:
'HOC based API is deprecated as of v10 and will be removed in v11.'
This means, as far as I understand, that such HOC functionality as injectSheet and withStyles will no longer be available in V11.
The new react-based stylesheet generating functions seem to be all based on react hooks. The function createUseStyles seemed very promising to myself and my team, until upon looking further into the source code we realised that it was only available within functional components, as it makes use of hooks.
The Problem
As a team we still make heavy use of React Class components and have no plans to move completely to hooks, not because hooks aren't useful, but because sometimes functional components aren't the best or most organised solution to writing a component.
Perhaps I'm missing something-- but it seems like there is now no solution left for React Class based components, other than writing our own manual implementation from core jss.
What solutions are there for a developer to make use of react-jss in a way similar to that achieved by createUseStyles, keeping up with the latest version of react-jss, being able to pass dynamic props, and etc. without writing a manual implementation?
While not specific to JSS, keep in mind that you can always use a tiny wrapper to convert any Hook to render prop or a HOC.
Converting Hook to a render prop is described here: https://reacttraining.com/blog/using-hooks-in-classes/
You can use a similar approach to convert any Hook to a HOC.
import { Classes } from 'jss';
import { createUseStyles } from 'react-jss';
First, lets create a more type safe function for creating styles.
export function createStyles(classes: { [name: string]: Partial<CSSStyleDeclaration> }) {
return createUseStyles(classes as any);
}
Secondly, we'll create a simple wrapper to allow hooks for our components.
function Styles<T extends string | number | symbol>(props: { styles: () => Classes<T>, children: (classes: Classes<T>) => ReactElement }) {
const classes = props.styles();
return props.children(classes);
}
Example
const styles = createStyles({
title: {
fontSize: '25px',
textTransform: 'uppercase'
},
message: {
color: 'red'
}
});
export const App = () => (
<Styles styles={styles}>
{classes => (
<Fragment>
<h1 className={classes.title}>Title</h1>
<p className={classes.message}>message</p>
</Fragment>
)}
</Styles>
);
Output

Aframe component with dependencies on component with multiple true

I am writing a custom component that I would like to define other component dependencies.
The dependencies are different animations types.
Let's say they have the names "animation__x" and "animation__y"
x and y can be any name, so I am looking for something like animation__*
or /animation__\s*/
The only way I have made this work at the moment is either ensuring my component is placed after the animation components on the HTML or alternatively to force update components using this.el.updateComponents()
Neither of these solutions feels right to me.
AFRAME.registerComponent('cool-component', {
dependencies: ['animation'],
update: functions(data){
//detect available animations and do some stuff with them
let animations = Object.keys(components).filter((key) => {
return /(^animation__\w*)/.test(key);
});
//animations results in an empty array
}
});
html that is not working
<a-scene cool-component animation__x="" animation__y="" animation__z=""></a-scene>
html that is working (but its not good as I cant ensure my component is always last in the list
<a-scene animation__x="" animation__y="" animation__z="" cool-component></a-scene>
js that works, but doesnt feel write as I am using the entities internal functions
AFRAME.registerComponent('cool-component', {
dependencies: ['animation'],
update: functions(data){
this.el.updateComponents(); //<-- I DONT LIKE THIS BUT IT WORKS
//detect available animations and do some stuff with them
//now all animations are available as this.el.components
let animations = Object.keys(components).filter((key) => {
return /(^animation__\w*)/.test(key);
});
}
});
Three options:
Depend on the specific component names: dependencies: ['animation__xxx']
Make cool-component set those animations:
AFRAME.registerComponent('cool-component', {
init: functions(data){
this.el.setAttribute('animation__xxx', {...});
}
});
You can also defer cool-component logic until the entity has loaded and all the components have initialized:
init: function () {
this.el.addEvenListener(‘loaded’, this.doStuffAferComponentsLoad.bind(this));
}
More details in what cool-component is trying to accomplish will help to get a more precise answer.

Css Selector in Framework7 vue

i try to build an Cordova/Phonegap application using vue.js and the Framework7.
I find out how to use functions like "onClick" using the "v-on:click="OnClick" attribute in an html element. Framework7 has jquery already implemented in the dom.
But there is one question. How can i access the dom directly, so that i can select whole css classes with the jquery selector. Like:
$('.likeButton'). ?
In the offical framework7 i found something like this to access the dom with its functions:
this.$$ or this.Dom7
This is what i have already written down in the home.vue file:
<script>
//import Fonts-awesome Icons
import FontAwesomeIcon from '#fortawesome/vue-fontawesome'
import {} from '#fortawesome/fontawesome-free-solid'
import F7Icon from "framework7-vue/src/components/icon";
import F7PageContent from "framework7-vue/src/components/page-content";
import * as Framework7 from "framework7";
export default {
name: 'FAExample',
components: {
F7PageContent,
F7Icon,
FontAwesomeIcon
},
methods: {
clickit: function () {
console.log("hi");
//this is what i have tested, looking if i have access to dom
let $$ = this.$$;
console.log($$);
},
//this is what i want to use
$('.likebutton').on('click',function () {
})
}
}
</script>
Did any of you have an idea how this works?
I hope you can help me. I'm new with vue.js in combination with the framework7.
Thank's for your help :)
We can use all the DOM functions just like
this.$$('.classname)
for example, if you want to hide something by jquery you can use as:
this.$$('.classname).hide()
To check all the DOM functions you can check the official documentation.
https://framework7.io/docs/dom7.html
But make sure that your DOM function should not in any Window function.
If you get the error to implemented it, just make the 'this' instance first.
Just like:
var self=this; // a global variable with this instance
use
self.$$('.classname).hide()
for any framework7 help, just ping me on skyp: sagardhiman5_1
Have you tried using Vue's $refs? You can set a reference to a specific DOM element and then access that in Vue.
A simple example:
<template>
<div class="some-item" ref="itemRef">Some item</div>
</template>
Then in the component:
var myItem = this.$refs.myItem;
// do what you want with that DOM item...
You can also access $refs from the parent. The example in the link below gives details on that.
More on $refs: https://v2.vuejs.org/v2/guide/components.html#Child-Component-Refs

Resources