Same code generating different snapshots on different machines - javascript

We're using git for version control, so the code is the same. But if I generate snapshots, and my coworkers run the tests, they all fail on the snapshot part. Why can this happen?
Example component
import React from 'react';
import styled from 'styled-components';
import classnames from 'classnames';
import { colors } from '../../utils/css';
const ProgressIcon = ({ className, progress, color }) => (
<div className={className}>
<div className={classnames('background', color)}>
<div className={classnames('icon', progress, color)}/>
</div>
</div>
);
export const StyledProgressIcon = styled(ProgressIcon)`
width: 12.8px;
height: 12.8px;
margin: 0;
div {
margin: 0;
}
.background.white {
border: 2px solid ${colors.LG_WHITE};
}
.background.gray {
border: 2px solid ${colors.LG_GRAY_2};
}
.background {
height: 100%;
width: 100%;
border-radius: 50%;
box-sizing: border-box;
.icon {
height: 100%;
}
.icon.white {
background: ${colors.LG_WHITE};
}
.icon.gray {
background: ${colors.LG_GRAY_2};
}
.icon.full {
width: 100%;
}
.icon.half {
width: 50%;
}
.icon.empty {
width: 0;
}
}
`;
Test
import React from 'react';
import { shallow } from 'enzyme';
import { StyledProgressIcon as ProgressIcon } from '../ProgressIcon';
describe('<ProgressIcon/>',
() => {
let wrapper;
beforeEach(() => {
wrapper = shallow(<ProgressIcon progress={'full'} color={'gray'}/>);
});
it('should match the snapshot', () => {
expect(wrapper).toMatchSnapshot();
});
});
I'm comparing the snapshots created by my coworkers (Everybody else's tests are passing with the exact same snapshots, and code. It only fails on my machine)
Here is the log
FAIL src/components/ProgressIcon/test/ProgressIcon.test.js
● <ProgressIcon/> › should match the snapshot
expect(received).toMatchSnapshot()
Snapshot name: `<ProgressIcon/> should match the snapshot 1`
- Snapshot
+ Received
## -4,11 +4,11 ##
Object {
"$$typeof": Symbol(react.forward_ref),
"attrs": Array [],
"componentStyle": ComponentStyle {
"componentId": "sc-bdVaJa",
- "isStatic": false,
+ "isStatic": true,
"rules": Array [
"
width: 12.8px;
height: 12.8px;
margin: 0;
## -69,11 +69,10 ##
"foldedComponentIds": Array [],
"render": [Function],
"styledComponentId": "sc-bdVaJa",
"target": [Function],
"toString": [Function],
- "usesTheme": false,
"warnTooManyClasses": [Function],
"withComponent": [Function],
}
}
forwardedRef={null}
10 | });
11 | it('should match the snapshot', () => {
> 12 | expect(wrapper).toMatchSnapshot();
| ^
13 | });
14 | });
15 |
at Object.toMatchSnapshot (src/components/ProgressIcon/test/ProgressIcon.test.js:12:23)
And the reverse is if I generate snapshots, and my coworkers test. Why is this happening and how can I fix this?

There is a version mismatch in your styled-components lib dependency. As explained
here
It is the styled component's shallow render that shows you that "isStatic": false value
Both of you need to sync up your dependencies. First
make sure that both have the same package.json.
Then the surefire way to do this is. In one of your computers
Remove node_modules
delete package-lock.json
Run npm install
Commit your package-lock.json! (ignore if no changes)
Go to all other PCs.
Pull in the changes to package lock json (reject all local and accept all remote changes).
Remove node_modules.
Run npm install.
Now run your tests and check, the snapshots should be equal.

I fixed it by installing https://github.com/styled-components/jest-styled-components
Although I've followed the above mentioned points as well but I think this one should also fix the issue.
yarn add --dev jest-styled-components
Usage
import React from 'react'
import styled from 'styled-components'
import renderer from 'react-test-renderer'
import 'jest-styled-components'
const Button = styled.button`
color: red;
`
test('it works', () => {
const tree = renderer.create(<Button />).toJSON()
expect(tree).toMatchSnapshot()
expect(tree).toHaveStyleRule('color', 'red')
})

Related

Undefined property testing Lit typescript web component

I recently converted a lit web component over to Typescript and can't seem to figure out why my tests are failing now.. everything was working fine before the conversion.
These are my dependencies for testing:
"#open-wc/testing": "^3.1.2",
"#web/dev-server-esbuild": "^0.2.16",
"#web/test-runner": "^0.13.27"
So I run "test": "web-test-runner", with the following config in web-test-runner.config.mjs (Also got the same error using tsc to transpile the code):
import { esbuildPlugin } from '#web/dev-server-esbuild';
const filteredLogs = ['Running in dev mode', 'Lit is in dev mode'];
export default /** #type {import("#web/test-runner").TestRunnerConfig} */ ({
files: 'lib/**/*.test.ts',
nodeResolve: {
exportConditions: ['browser', 'development'],
},
plugins: [esbuildPlugin({ ts: true })],
filterBrowserLogs(log) {
for (const arg of log.args) {
if (typeof arg === 'string' && filteredLogs.some(l => arg.includes(l))) {
return false;
}
}
return true;
}
});
and get this error:
components: > web-test-runner
components: Chrome: |██████████████████████████████| 0/1 test files | 0 passed, 0 failed
components: Running tests...
lib/MyElement/index.test.ts:
components: ❌ MyElement > has a default title "World" and count 0
components: AssertionError: expected undefined to equal 'World'
components: at o.<anonymous> (lib/MyElement/index.test.ts:11:23)
components: Chrome: |██████████████████████████████| 1/1 test files | 0 passed, 1 failed
components: Finished running tests in 2.7s with 1 failed tests.
components: npm ERR! code ELIFECYCLE
components: npm ERR! errno 1
components: npm ERR! components#1.0.0 test: `web-test-runner`
components: npm ERR! Exit status 1
components: npm ERR!
components: npm ERR! Failed at the components#1.0.0 test script.
components: npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
components: npm ERR! A complete log of this run can be found in:
components: npm ERR! /Users/shawn/.npm/_logs/2022-03-21T22_11_54_084Z-debug.log
lerna ERR! npm run test exited 1 in 'components'
This is the component code:
import {LitElement, html, css} from 'lit';
import {customElement, property, state} from 'lit/decorators.js';
#customElement('my-element')
export class MyElement extends LitElement {
static styles = css`
:host {
display: block;
border: solid 1px gray;
padding: 16px;
max-width: 800px;
}
`;
#property() name: string = 'World';
#state() count: number = 0;
_onClick() {
this.count++;
this.dispatchEvent(new CustomEvent('count-changed'));
}
sayHello(name: string) {
return `Hello, ${name}`;
}
render() {
return html`
<h1>${this.sayHello(this.name)}!</h1>
<button #click=${this._onClick} part="button">
Click Count: ${this.count}
</button>
<slot></slot>
`;
}
}
And finally, the test code:
import { html, fixture, expect } from '#open-wc/testing';
import { MyElement } from '.';
describe('MyElement', () => {
it('has a default title "World" and count 0', async () => {
const el = await fixture<MyElement>(html`
<my-element></my-element>
`);
expect(el.name).to.equal('World');
expect(el.count).to.equal(0);
});
});
So I believe it's something related to transpiling the typescript, but I have not been successful in finding out what exactly it is. Anybody notice anything wrong that would cause these properties to be undefined now?
EDIT:
This is the original JS implementation to show the diff between this and the TS one.
import {LitElement, html, css} from 'lit';
export class MyElement extends LitElement {
static get styles() {
return css`
:host {
display: block;
border: solid 1px gray;
padding: 16px;
max-width: 800px;
}
`;
}
static get properties() {
return {
name: {type: String},
count: {type: Number},
};
}
constructor() {
super();
this.name = 'World';
this.count = 0;
}
render() {
return html`
<h1>${this.sayHello(this.name)}!</h1>
<button #click=${this._onClick} part="button">
Click Count: ${this.count}
</button>
<slot></slot>
`;
}
_onClick() {
this.count++;
this.dispatchEvent(new CustomEvent('count-changed'));
}
sayHello(name) {
return `Hello, ${name}`;
}
}
window.customElements.define('my-element', MyElement);
Can you try
#property({type: String}) name = 'World';
https://lit.dev/docs/api/decorators/#property
The issue is that you're not using the instance of MyElement in your test file but only its type and tag. Thus the compile process will throw out the import statement import { MyElement } from '.';. If you would compile your test file using tsc you would see that the import statement is missing in the .js-output.
Fix it by importing the whole file in your test:
import './index.js';
Note: In the test file of the lit-element-starter-ts repo (find it here) this scenario is not appearing since they are using the Element's instance in their first test case, thus the named import won't be removed by the tsc/esbuild:
import {MyElement} from '../my-element.js';
// ...
test('is defined', () => {
const el = document.createElement('my-element');
assert.instanceOf(el, MyElement);
});

Gatsby not loading useEffect function in production

I'm creating a website using Gatsby.js.
In my component, I'd created animation using Gsap, inside useEffect function.
While debugging, all works. In production the useEffect function not running, what follows to not showing animations.
What I should do?
Any ideas?
Thanks for answers!
My component:
import React, { useRef, useEffect } from "react"
import styled from "styled-components"
import gsap from "gsap"
import WhatEver from "../../../static/whatever.svg"
import { FontAwesomeIcon } from '#fortawesome/react-fontawesome'
import { faArrowDown } from '#fortawesome/free-solid-svg-icons'
import scrollTo from 'gatsby-plugin-smoothscroll';
const HeaderWrapper = styled.header`
width: 100%;
height: 100vh;
min-height: 150px;
padding: 10px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background-color: rgb(255, 216, 41);
`
const HeaderButton = styled.button`
display: block;
margin: 40px auto;
border: 2px solid #000000;
`
const HeaderComponent = () => {
const animWrapper = useRef(null)
useEffect(() => {
const [elements] = animWrapper.current.children
const what = elements.getElementById('What')
const ever = elements.getElementById('Ever')
const button = document.getElementById('header-button')
const icon = document.getElementById('header-icon')
const whatChildrens = what.children
const everChildrens = ever.children
const allChildrens = [...whatChildrens, ...everChildrens]
gsap.set([...allChildrens, button], { autoAlpha: 0 })
const timeLine = gsap.timeline({ defaults: { ease: 'power3.inOut' } })
timeLine
.to(whatChildrens, { autoAlpha: 1, duration: 0.75 })
.to(everChildrens, { autoAlpha: 1, stagger: 0.025 })
.to(button, { autoAlpha: 1 })
}, [])
return (
<HeaderWrapper className="header" id="main-header">
<div ref={animWrapper} id="header-logo-wrapper">
<WhatEver style={{width: '100%'}}/>
<HeaderButton id="header-button" onClick={() => scrollTo('#poznaj-nas')}>
<FontAwesomeIcon icon={faArrowDown} id="header-icon"/>
</HeaderButton>
</div>
</HeaderWrapper>
)
}
export default HeaderComponent
I think what is happening is that the gsap library is getting tree shaken out of the production build. I would either try adjusting your webpack settings to make sure that it is not removed, or include it like this instead:
const gsap = require("gsap")
Which in my experience has prevented libraries from being tree shaken out.
I was facing this issue and it got resolved just by following the steps:
If you are trying to open the html directly without any web server then useEffect won't be called.
Only way to solve this issue is by running a webserver and serve the html from the server.
I am using a mac system so run the python server using the command inside the public folder:
python -m SimpleHTTPServer 8000
then open it using localhost:8000

Styled Components Nested components erroring

I am trying to workout why this is erroring.
Although If I do not have CardWrapper wrapping around CardImage the image is displaying.
import React from 'react'
import styled, { css } from 'styled-components'
const CardWrapper = styled.div`
background-color: yellow;
border-color: 1px solid red;
position: relative;
`
const CardImage = styled.img`
height: auto;
width: 100%;
`
const Card = props => {
return (
<CardWrapper>
<CardImage src={props.data.imageUrl}/>
</CardWrapper>
)
}
export default Card;
App.js
<Card data={{imageUrl: 'https://via.placeholder.com/630x354', logoUrl: "https://via.placeholder.com/100x100", text: "test"}}/>
Error
./src/Components/Card/Card.js
Error: Cannot find module '/Users/max/test/test/test/node_modules/babel-preset-react-app/node_modules/#babel/core/lib/index.js'. Please verify that the package.json has a valid "main" entry
Looks like you need to install a Node.js package. In your terminal, navigate to the project's root directory and run:
npm install babel-preset-react-app

Can't access global SCSS variables in Storybook with Webpack + React

Trying to get access to global SCSS variables like I have in the rest of my app. I've taken it so far but I'm currently getting this error with the .storybook.scss test file;
The .storybook directory and the src directory are siblings.
-/.storybook
|-config.ts
|-storybook.scss
|-webpack.config.js
-/src
|-/components/
|-/scss/
|-global.scss
ERROR in ./src/components/Global/Dialog/dialog.scss (./node_modules/react-scripts/node_modules/css-loader??ref--8-1!./node_modules/postcss-loader/src??postcss!./node_modules/sass-loader/lib/loader.js??ref--8-3!./node_modules/style-loader!./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/lib/loader.js!./src/components/Global/Dialog/dialog.scss)
Module build failed (from ./node_modules/sass-loader/lib/loader.js):
.modal {
^
Invalid CSS after "": expected 1 selector or at-rule, was "var content = requi"
in /Users/hghazni/Sites/eat/src/components/Global/Dialog/dialog.scss (line 1, column 1)
I've attempted to use many different webpack.config.js and config.ts configurations and followed the official documentation on the Storybook website but had no luck.
webpack.config.js
const { resolve } = require('path');
module.exports = {
module: {
rules: [
{
test: /\.scss$/,
loaders: ['style-loader', 'css-loader', 'sass-loader'],
include: path.resolve(__dirname, '../src/scss')
},
{
test: /\.css$/,
loader: 'style-loader!css-loader',
include: __dirname
}
]
}
}
config.ts
import { configure } from "#storybook/react";
require('./storybook.scss');
const req = require.context('../src/', true, /.stories.tsx$/);
function loadStories() {
req.keys().forEach((filename) => req(filename))
}
configure(loadStories, module);
.storybook.scss
body {
background: $color-primary;
}
Dialog.tsx
import React from 'react'
import './dialog.scss';
type DialogType = {
onClose: any;
isOpen: any;
}
const Dialog: React.SFC<any> = props => {
let dialog: any = (
<div className={"dialog " + props.dialogClass}>
<button className={"dialogClose"} onClick={props.onClose}>X</button>
<div>{props.children}</div>
</div>
);
if (!props.isOpen) {
dialog = null;
}
return (
<div className="modal">
{dialog}
</div>
)
}
export default Dialog;
dialog.scss
.modal {
position: absolute;
top: 20%;
left: 50%;
-webkit-transform: translate(-50%);
transform: translate(-50%);
width: 95%;
#include media-query(min, $desk-start) {
width: 70%;
max-width: $desk-start;
}
}
.dialog {
border: 4px dashed rgba(47, 144, 189, 0.411);
border-radius: $half-spacing;
padding: $base-spacing;
background: $color-base;
}
.dialogClose {
position: absolute;
top: 0;
right: 0;
padding: $half-spacing;
background: $color-base;
border: 1px solid rgba(47, 144, 189, 0.411);
color: rgba(47, 144, 189, 1);
border-radius: 50px;
padding: $half-spacing 12.5px;
&:hover {
cursor: pointer;
}
}
I'm looking for any support/guidance on how to get storybook to be able to load my SCSS variables located in ../src/scss/global.scss.
So what Storybook or the documentation doesn't explicitly tell you is that having two webpack configs isn't ideal. You'll need to basically cater for a lot of the things needed in your main webpack config if you're trying to mirror your components.
Though there is a way to have to one webpack config with all the options separated so you can reuse it across the site as many times as you need. I even wrote an article about how to do it and built a boiler plate template for you with it already setup if you want to check it out.
https://levelup.gitconnected.com/a-killer-storybook-webpack-config-a0fd05dc70a4
Had same kind of issue, then found that Storybook supports scss configuration out of the box, I removed all rules related to sass/scss from storybook webpack config override and everything worked. However npm i node-sass was needed

Testing DOM in Enzyme

Let's say I have a tiny component like this:
Button.js
import React from 'react';
import './Button.css';
export default class Button extends React.Component {
render() {
return (
<a href={ this.props.url } className={`button button-${ this.props.type }`}>
{ this.props.content }
</a>
);
}
}
And there's some super basic styling like this:
Button.css
.button {
color: white;
padding: 1em;
border-radius: 5px;
text-decoration: none;
}
.button-primary {
background-color: red;
}
.button-primary:hover {
background-color: darkred
}
.button-secondary {
background-color: aqua;
color: black;
}
.button-secondary:hover {
background-color: darkcyan;
color: white;
}
And let's say I want to write some tests for this:
Button.test.js
import React from 'react';
import Enzyme, {shallow, mount} from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
Enzyme.configure({adapter: new Adapter()});
import Button from './Button';
import './Button.css';
// Render buttons
const primaryButton = mount(
<Button
content="Primary button"
url="http://www.amazon.co.uk"
type="primary"
/>
);
const secondaryButton = mount(
<Button
content="Secondary button"
url="http://www.ebay.co.uk"
type="secondary"
/>
);
it('should exist', () => {
expect(primaryButton).toBeDefined();
expect(secondaryButton).toBeDefined();
});
it('should display text in the button', () => {
expect(primaryButton.text()).toEqual('Primary button');
});
it('should have the correct CSS classes', () => {
expect(primaryButton.find('.button').hasClass('button-primary')).toEqual(true);
expect(secondaryButton.find('.button').hasClass('button-secondary')).toEqual(true);
});
I've set this up using react-create-app and all the above works perfectly.
My question is: how do I test that what is getting rendered looks correct? For example, in this case I would want to make sure that the buttons have the correct background colours defined in the CSS file and that they have the correct border radius. This will prevent other developers accidentally overriding critical styling for example.
I was under the impression that Enzyme did this out of the box, but I cannot understand how to interrogate the virtual DOM which I assume is happening in the background? I thought that JSDOM was automatically running and I'm executing this from the CLI which is a Node environment.
I've tried this so far:
it('should have the correct background colours', () => {
const domNode = primaryButton.find('.button').at(0).getDOMNode();
const background = getComputedStyle(domNode).getPropertyValue('background');
expect(background).toBe('red');
});
But background is returned blank, in fact if I do console.log(getComputedStyle(domNode)) I get this returned which seems to be missing the styles:
console.log src/modules/Button/Button.test.js:42
CSSStyleDeclaration {
_values: {},
_importants: {},
_length: 0,
_onChange: [Function] }
The getDOMNode of an enzyme wrapper gets you the corresponding DOM node.
You can then use getComputedStyle to get the style of that DOM:
const renderedComponent = mount(<MyComponent /);
const domNode = renderedComponent.find('div').at(0).getDOMNode();
const background = getComputedStyle(domNode).getPropertyValue('background');
expect(background).toBe('red');

Categories

Resources