React test fails becasue target container is not a DOM element - reactjs

I'm trying to run component tests and the tester keeps on failing because the target container is not a DOM element. I found an answer that recommended removing exported values from index.tsx but it did not fix the issue.
src/Component/__tests__/FirstPage.test.tsx
● Test suite failed to run
Target container is not a DOM element.
8 | export const socket = io('http://localhost:8080');
9 |
> 10 | ReactDOM.render(
| ^
11 | <React.StrictMode>
12 | <App/>
13 | </React.StrictMode>,
at Object.render (node_modules/react-dom/cjs/react-dom.development.js:26091:13)
Here is my App.tsx file
import React, { Component } from "react";
import './App.css';
import FirstPage from './Component/FirstPage/FirstPage';
export default class App extends Component {
render() {
return (
<FirstPage/>
);
}
}
Here is the index.tsx file:
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import io from 'socket.io-client';
import App from './App';
import reportWebVitals from './reportWebVitals';
export const socket = io('http://localhost:8080');
ReactDOM.render(
<React.StrictMode>
<App/>
</React.StrictMode>,
document.getElementById('root')
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint
reportWebVitals();
And here is the test
import { render, screen } from '#testing-library/react';
import userEvent from '#testing-library/user-event';
import React from 'react';
import FirstPage from '../FirstPage/FirstPage';
import User from '../User/User';
const testUser = new User("testUser", "id")
test('Test if FirstPage includes enter lobby button', () => {
render(<FirstPage/>);
const textElement= screen.getByText(/Enter Lobby!s/i);
expect(textElement).toBeInTheDocument();
});
Here is my index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico"/>
<meta
name="viewport"
content="width=device-width, initial-scale=1, shrink-to-fit=no"
/>
<meta name="theme-color" content="#000000"/>
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>

Edit
After spending some time on your project I found out what was causing this issue with your tests. In some of the components that FirstPage is using, you were importing socket like that
import { socket } from "../.."
This caused unexpected behaviour in the tests because the path was wrong.
To fix this, I took the socket export from index.tsx and put it in App.tsx and wherever you need to import it you can just do lit like this
import { socket } from "../../App"
That resolves the issues with the tests. Also, the improvements mention above still apply for cleaner code .
First of all, in your App.tsx you are importing FirstPage and name it as Greeting but then you are returning FirstPage in your component. You need to either return Greeting or rename the import to FirstPage. Also, you need to import React in order for the code to work. Even if you don't use React explicitly, you still need to import it because JSX is tranpiled to React.createElement() which uses React.
// App.tsx
import React, { Component } from "react";
import FirstPage from "./Component/FirstPage/FirstPage";
export default class App extends Component {
render() {
return <FirstPage />;
}
}
Moving on to your test, it's a good practice to put all the tests inside __tests__ folder. Also, it looks like you don't actually import FirstPage as well and then try to use it. Try importing it and running the tests again with the proposed changes in the App.tsx.
// /Components/FirstPage/__tests__/FirstPage.test.tsx
import React from "react";
import { render, screen } from "#testing-library/react";
import FirstPage from '../FirstPage';
test("Test if FirstPage includes enter lobby button", () => {
render(<FirstPage />);
...
});
I've tried it in the codesandbox and the tests worked.

Related

Problemn with MultiPage app that adds react widget, how to add it to other pages not only the index.html

I built a normal HTML/JS/CSS website and am Adding a widget( a code form made with react ) that I compile and export as a js and css to the index.html page by doing so:
<head>
<script src="https://unpkg.com/react#16.13.1/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom#16.13.1/umd/react-dom.development.js"></script>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="app"></div>
<link href="app.css" rel="stylesheet"/>
<script src="app.js"></script>
</body>
And I"m compiling the app with:
//yarn parcel , or npm run parcel
"parcel": "parcel build src/index.js --no-minify --no-source-maps -d widget && cp build/static/css/*.css widget/index.css",
React js script that get's the component and then add it to the element with id.
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
const app = document.getElementById('app')
ReactDOM.render(
(<React.StrictMode>
<App />
</React.StrictMode>),
app
);
After compiling I tried to make a secondpage serving it in another route, like blog.html and add the component too as I did with head and body, but the page remains blank. What could it be ? ( there are no logs in the console).
//the first html served
files_routes.get('/', (request, response) => {
response.sendFile('index.html', { root: '../build' })
});
//the second html which doesn't work
files_routes.get('/blog', (request, response) => {
response.sendFile('blog.html', { root: '../build' })
});
I couldn't replicate the issue in the newer code base. So I'll be closing this question...

How to break out of Next/React import hell?

After using Vue and Nuxt for more than a year, I decided to learn React and Next.js and almost immediately noticed the horrible Developer Experience.
Every stylesheet and component needs to be imported so there's always bloated import hell at the start of each component.
Not to mention if you need an extra library as you can't hook into any global object like Nuxt's this.$plugin option.
Is there some package to manage these imports for Nextjs? As far as I know, everyone who uses it doesn't mind it and that's what surprises me.
This Question may come as an insult to React and it is, but I just want at least one reason to join the hype-train as to why React is more popular.
create a file in pages directory named it _doucument.js or _document.ts (for TypeScript) and import React in it like below :
(below codes are TypeScript)
import React from 'react';
import Document, {
DocumentContext,
Head,
Html,
Main,
NextScript,
} from 'next/document';
export default class CustomDocument extends Document {
static async getInitialProps(ctx: DocumentContext) {
const initialProps = await Document.getInitialProps(ctx);
return { ...initialProps };
}
render() {
return (
<Html lang="en">
<Head>
<title>Your title</title>
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
}
and any more doesn't require that import React in any components.

TypeError: The 'compilation' argument must be an instance of Compilation in Shopify

I do shopify react tutorial.
But MyApp shown this error.
./node_modules/#shopify/polaris/dist/styles.css
TypeError: The 'compilation' argument must be an instance of Compilation
How can I fix it?
Package
version
Node
15.9.0
npm
7.5.3
yarn
1.22.10
#shopify/koa-shopify-auth
^3.2.8
#shopify/polaris
^6.0.1
#zeit/next-css
^1.0.1
dotenv
^8.2.0
isomorphic-fetch
^3.0.0
koa
^2.13.1
koa-session
^6.1.0
next
^10.0.7
react
^17.0.1
react-dom
^17.0.1
webpack
^5.23.0
This is my code.
import App from 'next/app';
import Head from 'next/head';
import React from 'react';
import { AppProvider } from '#shopify/polaris';
import translations from '#shopify/polaris/locales/en.json';
import '#shopify/polaris/dist/styles.css';
class MyApp extends App {
render() {
const { Component, pageProps } = this.props;
return (
<React.Fragment>
<Head>
<title>Sample App</title>
<meta charSet="utf-8" />
</Head>
<AppProvider i18n={ translations }>
<Component {...pageProps} />
</AppProvider>
</React.Fragment>
);
}
}
export default MyApp;
You can remove the next.config.js file and it will work as expected. The tutorial is old. Next.js supports css in v 10.

Using react-snap for SEO

I'm using react snap for SEO.
Here's what I did.
I added the following to index.js in my react application
import React from 'react';
import { hydrate, render } from "react-dom";
const rootElement = document.getElementById("root");
if (rootElement.hasChildNodes()) {
hydrate(<App />, rootElement);
} else {
render(<App />, rootElement);
}
Then I added the following to package.json
"postbuild": "react-snap"
When I run npm run build, and do View Source on the pages, I don't see the real time meta description and title that I need for the page.
What am I doing wrong?
Here's how I set the meta tags.
In BookDetail.jsx
import {Helmet} from "react-helmet";
<Helmet>
<meta charSet="utf-8" />
<title>{this.state.book.title} by {this.state.book.author} | Sumizeit</title>
<meta name="description" content={this.state.book.desc}/>
</Helmet>
do not use react-snap just change to next.js (react-snap so many problems: refresh error on protected routes, build time no joke, inline css)...by the way there is nothing wrong in your code

React Meta Tags Server Side

I have completed the meta tags implementation in react js at client side using react document meta and my title has changed.However I am confused about the server side prerendering for meta tags.I am completely new at this.I have gone through links like React-document-data and Npm React-document-meta but could not get through server side rendering.Would appreciate any help
Ok I've been doing this recently with expressjs and I think I've cracked it!
Firstly you're going to want to make one singular instance of your react 'app' which will be babel-ified. I tend to stick everything in an src and babel it to dist. My main for the server then ends up being /dist/index.js and this includes my app using `dist/App/index.js.
Next you're going to want to make your assets because rendering locally within a node process is very different to on a DOM.
Ok so firstly src/index.js
import express from 'express';
import app from './App';
import Mailgun from 'mailgun-js';
const server = express();
server.use(express.static('public'));
const port = process.env.SERVER_PORT || 3000;
server.get('/*', function(request, response) {
response.send(app());
});
This is my App/index.js file which is my initial content not my react app!
import * as assets from './../Assets';
import App from './app';
import React from 'react';
import {renderToString} from 'react-dom/server';
import {Provider} from 'react-redux';
import createStore from './Store';
import reducers from './Reducers';
import sagas from './Sagas';
//const browserHistory = createBrowserHistory();
const store = createStore({}, reducers, sagas);
const html = renderToString(
<Provider store={store}>
<App />
</Provider>
);
export default function render () {
return `<!doctype html>
<html prefix="og: http://ogp.me/ns#">
<head lang="en">
<meta charset="UTF-8">
<title>Preloaded title</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
</head>
<body>
<link rel="stylesheet" href="build/${assets.get('index.css')}"/>
<div id="root">${html}</div>
<div id="fb-root"></div>
<script type="text/javascript">
// WARNING: See the following for security issues around embedding JSON in HTML:
// http://redux.js.org/docs/recipes/ServerRendering.html#security-considerations
window.__PRELOADED_STATE__ = ${JSON.stringify(store.getState()).replace(/</g, '\\u003c')}
</script>
<script type="text/javascript" src="build/${assets.get('index.js')}"></script>
</body>
</html>`;
}
the assets.get() function is essentially returning a full url to my assets based on a manifest file. Ignore this for now. Not particularly important.
That's essentially it for pre-rendering. Now you'll need a different version for the build js for rehydrating your react app.
So assets/js/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux'
import createStore from './../../src/App/Store';
import {createBrowserHistory} from 'history';
import reducers from './../../src/App/Reducers';
import sagas from './../../src/App/Sagas';
import App from './../../src/App/app';
const preloadedState = window.__PRELOADED_STATE__;
// Allow the passed state to be garbage-collected
delete window.__PRELOADED_STATE__;
preloadedState.server.env = false;
const browserHistory = createBrowserHistory();
const store = createStore(browserHistory, reducers, sagas, preloadedState);
ReactDOM.hydrate(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root'));
notice ReactDOM.hydrate not ReactDOM.render.
In this file you can add your google analytic etc. Anything to do with the DOM/window, DOM load etc.
And that's essentially it! I used the below example to work from.
https://redux.js.org/docs/recipes/ServerRendering.html

Resources