react-dom.development.js?61bb:530 Warning: Prop className did not match - material-ui

react-dom.development.js?61bb:530 Warning: Prop className did not match.
Server: "MuiTypography-root makeStyles-root-32 makeStyles-root-47 makeStyles-darkest-27 makeStyles-bodySmall-43 makeStyles-noTextTransform-41 MuiTypography-body1"
Client: "MuiTypography-root makeStyles-root-32 makeStyles-root-48 makeStyles-darkest-27 makeStyles-bodySmall-43 makeStyles-noTextTransform-41 MuiTypography-body1"
I have tried the following so far to no avail:
configured runtime chunk in webpack, as we are code splitting at the route level,
optimization: {
runtimeChunk: {
name: 'app',
},
},
verified there is only one version of material-ui, the latest, 4.9.3
node environment is the same for both client and server
tried wrapping both the client and app in stylesprovider with a fresh createGenerateClassName:
server:
const sheets = new ServerStyleSheets();
const generateClassName = createGenerateClassName({
productionPrefix: 'tock',
});
const html = ReactDomServer.renderToString(
sheets.collect(
<Provider store={store}>
<StaticRouter location={req.url} context={routerContext}>
<StylesProvider generateClassName={generateClassName}>
<Application />
</StylesProvider>
</StaticRouter>
</Provider>
)
);
as well as ensuring that new ServerStyleSheets is created on every requuest.
client:
const generateClassName = createGenerateClassName({
productionPrefix: 'tock',
});
try {
(fullRender ? ReactDOM.render : ReactDOM.hydrate)(
<StrictMode>
<Provider store={store}>
<Router history={tockHistory}>
<StylesProvider generateClassName={generateClassName}>
<Routes />
</StylesProvider>
</Router>
</Provider>
</StrictMode>,
document.querySelector('#Root')
);
} catch (e) {
// eslint-disable-next-line no-console
console.error(e);
throw e;
}
followed the reference implementation:
https://material-ui.com/guides/server-rendering/
this seems to only be happening in development mode. If I bundle for production and run the app, it's working.
worked through:
https://material-ui.com/getting-started/faq/#my-app-doesnt-render-correctly-on-the-server
specifically, I was interested in this:
https://material-ui.com/getting-started/faq/#react-class-name-hydration-mismatch
Node: v13.8.0
Webpack: 4.41.6
Material-ui: 4.9.3
the component where we started seeing this issue, interestingly, uses some prop based styles:
export const useTypographyStyles = makeStyles((theme) => ({
root: {
marginBottom: ({ mb, paragraph }: TypographyProps) =>
paragraph ? theme.spacing(2) : theme.spacing(mb ?? 0),
},
which I notice generates 2 strings for the classes in the hook.
root: "makeStyles-root-32 makeStyles-root-232"
is what I get when I log the result of:
const classes = useTypographyStyles({ mb, paragraph });
but if I do a regular style there with just a value, I do not get the issue.

I know this isn't much help but changing the specific error triggering className worked for me. I had a class called EmojiWrapper and it was giving the error of client/server difference. So I renamed it and the problem went away. I think it has something to do with caching.

Related

In SolidJS, How Do I Do a Fallback Route?

I'm new to Solid JS, coming mainly from a React background. I'm using Solid and Solid-App-Router right now for the first time.
I'm trying to design routes with a fallback, meaning if an endpoint is put into the URL that does not exist, it will redirect to a default location. My problem is this fallback is executing no matter what, overriding all my other routes.
I'll add that namedLazy works great and is simply a wrapper to support named exports with SolidJS lazy(). Here is my routing code:
import { namedLazy } from '../../utils/solidWrappers';
import { Routes, Route } from 'solid-app-router';
import { isAuthenticated } from '../../resources/AuthResources';
const Welcome = namedLazy(() => import('./Welcome'), 'Welcome');
const Categories = namedLazy(() => import('./Categories'), 'Categories');
const Redirect = namedLazy(() => import('../UI/Redirect'), 'Redirect');
export const AppRoutes = () => {
return (
<Routes>
<Route path="/welcome" element={<Welcome />} />
{isAuthenticated() && (
<Route path="/categories" element={<Categories />} />
)}
<Route path="*" element={<Redirect />} />
</Routes>
);
};
And here is my Redirect component:
import { useNavigate } from 'solid-app-router';
export const Redirect = () => {
const navigate = useNavigate();
navigate('/welcome');
return <></>;
};
This kind of fallback route design works in react-router, however it's not working for me with solid-app-router. This is not the only route design, I also tried the configuration/array based route design as well and had the same problem. I'm open to suggestions for how to properly implement this functionality.
As the other commenter said, my code for the fallback route actually does work. This was a reactivity issue.
When the page first loads, isAuthenticated() returns false, because the authentication check is an ajax call that hadn't run yet. Therefore the /categories route wouldn't be rendered, and if I was trying to manually navigate to /categories I would instead by redirected. This made it appear as though the catch-all route was overriding everything, when in fact it was behaving as expected.
I added another check to prevent the routes from rendering until after the authentication check ajax call was made, and then everything worked perfectly.

Mocking authentication when testing MSAL React Apps

Our app is wrapped in the MSAL Authentication Template from #azure/msal-react in a standard way - key code segments are summarized below.
We would like to test app's individual components using react testing library (or something similar). Of course, when a React component such as SampleComponentUnderTest is to be properly rendered by a test as is shown in the simple test below, it must be wrapped in an MSAL component as well.
Is there a proper way to mock the MSAL authentication process for such purposes? Anyway to wrap a component under test in MSAL and directly provide test user's credentials to this component under test? Any references to useful documentation, blog posts, video, etc. to point us in the right direction would be greatly appreciated.
A Simple test
test('first test', () => {
const { getByText } = render(<SampleComponentUnderTest />);
const someText = getByText('A line of text');
expect(someText).toBeInTheDocument();
});
Config
export const msalConfig: Configuration = {
auth: {
clientId: `${process.env.REACT_APP_CLIENT_ID}`,
authority: `https://login.microsoftonline.com/${process.env.REACT_APP_TENANT_ID}`,
redirectUri:
process.env.NODE_ENV === 'development'
? 'http://localhost:3000/'
: process.env.REACT_APP_DEPLOY_URL,
},
cache: {
cacheLocation: 'sessionStorage',
storeAuthStateInCookie: false,
},
system: {
loggerOptions: {
loggerCallback: (level, message, containsPii) => {
if (containsPii) {
return;
}
switch (level) {
case LogLevel.Error:
console.error(message);
return;
case LogLevel.Info:
console.info(message);
return;
case LogLevel.Verbose:
console.debug(message);
return;
case LogLevel.Warning:
console.warn(message);
return;
default:
console.error(message);
}
},
},
},
};
Main app component
const msalInstance = new PublicClientApplication(msalConfig);
<MsalProvider instance={msalInstance}>
{!isAuthenticated && <UnauthenticatedHomePage />}
{isAuthenticated && <Protected />}
</MsalProvider>
Unauthenticated component
const signInClickHandler = (instance: IPublicClientApplication) => {
instance.loginRedirect(loginRequest).catch((e) => {
console.log(e);
});
};
<UnauthenticatedTemplate>
<Button onClick={() => signInClickHandler(instance)}>Sign in</Button>
</UnauthenticatedTemplate>
Protected component
<MsalAuthenticationTemplate
interactionType={InteractionType.Redirect}
errorComponent={ErrorComponent}
loadingComponent={LoadingComponent}
>
<SampleComponentUnderTest />
</MsalAuthenticationTemplate>
I had the same issue as you regarding component's test under msal-react.
It took me a couple of days to figure out how to implement a correct auth mock.
That's why I've created a package you will find here, that encapsulates all the boilerplate code : https://github.com/Mimetis/msal-react-tester
Basically, you can do multiple scenaris (user is already logged, user is not logged, user must log in etc ...) in a couple of lines, without having to configure anything and of course without having to reach Azure AD in any cases:
describe('Home page', () => {
let msalTester: MsalReactTester;
beforeEach(() => {
// new instance of msal tester for each test
msalTester = new MsalReactTester();
// spy all required msal things
msalTester.spyMsal();
});
afterEach(() => {
msalTester.resetSpyMsal();
});
test('Home page render correctly when user is logged in', async () => {
msalTester.isLogged();
render(
<MsalProvider instance={msalTester.client}>
<MemoryRouter>
<Layout>
<HomePage />
</Layout>
</MemoryRouter>
</MsalProvider>,
);
await msalTester.waitForRedirect();
let allLoggedInButtons = await screen.findAllByRole('button', { name: `${msalTester.activeAccount.name}` });
expect(allLoggedInButtons).toHaveLength(2);
});
test('Home page render correctly when user logs in using redirect', async () => {
msalTester.isNotLogged();
render(
<MsalProvider instance={msalTester.client}>
<MemoryRouter>
<Layout>
<HomePage />
</Layout>
</MemoryRouter>
</MsalProvider>,
);
await msalTester.waitForRedirect();
let signin = screen.getByRole('button', { name: 'Sign In - Redirect' });
userEvent.click(signin);
await msalTester.waitForLogin();
let allLoggedInButtons = await screen.findAllByRole('button', { name: `${msalTester.activeAccount.name}` });
expect(allLoggedInButtons).toHaveLength(2);
});
I am also curious about this, but from a slightly different perspective. I am trying to avoid littering the code base with components directly from msal in case we want to swap out identity providers at some point. The primary way to do this is to use a hook as an abstraction layer such as exposing isAuthenticated through that hook rather than the msal component library itself.
The useAuth hook would use the MSAL package directly. For the wrapper component however, I think we have to just create a separate component that either returns the MsalProvider OR a mocked auth provider of your choice. Since MsalProvider uses useContext beneath the hood I don't think you need to wrap it in another context provider.
Hope these ideas help while you are thinking through ways to do this. Know this isn't a direct answer to your question.

How to use Mapbox geocoder with Quasar select?

I'm trying to create an Autocomplete component using the Mapbox Geocode API and Quasar's <q-select /> component. It appears though that Mapbox requires using their input (could be wrong about this), so I'm having trouble hooking it up to the select.
I've tried using the #mapbox/mapbox-gl-geocoder, vue-mapbox-ts and v-mapbox-geocoder libraries now. The two third-party libraries had some issues with them, so I'd prefer to use the one direct from Mapbox if possible.
<template>
<q-select
v-model="state.location"
:options="state.locations?.features"
:option-value="(result: MapboxGeocoder.Result) => result.place_name"
:option_label="(result: MapboxGeocoder.Result) => result.place_name"
:loading="state.loadingResults"
clear-icon="clear"
dropdown-icon="expand_more"
clearable
outlined
use-input
dense
label="Location">
<template #prepend>
<q-icon name="place " />
</template>
</q-select>
</template>
<script lang='ts' setup>
import { reactive, ref, onMounted } from 'vue';
import MapboxGeocoder from '#mapbox/mapbox-gl-geocoder';
const accessToken = import.meta.env.VITE_MAPBOX_ACCESS_TOKEN as string;
const state = reactive({
first_name: auth.currentUser?.first_name || undefined,
last_name: auth.currentUser?.last_name || undefined,
location: undefined,
locations: undefined as undefined | MapboxGeocoder.Results,
loadingResults: false,
geocoder: null as null | MapboxGeocoder,
});
onMounted(() => {
state.geocoder = new MapboxGeocoder({
accessToken,
types: 'country,region,place,postcode,locality,neighborhood',
});
state.geocoder?.on('result', (e) => {
console.log('on result: ', e);
});
state.geocoder?.on('results', (e) => {
console.log('results: ', e);
state.locations = e.features;
});
state.geocoder?.on('loading', (e) => {
console.log('loading');
state.loadingResults = true;
});
});
</script>
In the code sample above, none of the console logs are being run. If I add an empty <div id="geocoder" /> and then use the state.geocoder.addTo('#geocoder') function, it renders the Mapbox input and hits the console logs, but then I am unable to use the Quasar select like I'm hoping to.
How can I go about accomplishing this?
I never tracked down the reason why your seemingly correct syntax failed, but if I used this alternative:
const function results(e) {
console.log('results: ', e);
state.locations = e.features;
}
state.geocoder?.on('results', results);
everything magically worked.
MapboxGeocoder is a UI control, it's not meant to be used in a "headless" mode.
As you create your own control, you could just use the Mapbox Geocoder API, see https://docs.mapbox.com/api/search/geocoding/ for more information on how this works.

StatusBar does not have web implementation

I'm trying to render a component using react-testing-library in an Ionic React based project. There appears to be an issue with StatusBar. The error says StatusBar does not have web implementation.
My code looks something like this:
let component
beforeEach(() => {
component = render(
<ThemeProvider>
<IonReactRouter>
<IonRouterOutlet>
<Login />
</IonRouterOutlet>
</IonReactRouter>
</ThemeProvider>
)
})
describe('snapshot', () => {
it('should match snapshot', () => {
const { asFragment } = component
expect(asFragment()).toMatchSnapshot()
})
})
That's no error, that's the Capacitor Plugin not having the Web Implementation, you could just ignore that or catch it everywhere with .catch(()=>{});
Have you installed #capacitor/status-bar in /src-capacitor? (yarn add #capacitor/status-bar or npm install ....)

aurelia/skeleton-plugin cant run test on custum element

i have created an aurelia plugin using the skelton-plugin https://github.com/aurelia/skeleton-plugin i am now looking at writing unit tests for it.
i am stuggling to get a unit test running for a custom element ive added to the project. i started with the 'testing a custom element' example from http://aurelia.io/hub.html#/doc/article/aurelia/testing/latest/testing-components/3
template:
<template>
<div class="firstName">${firstName}</div>
</template>
vm
import {bindable} from 'aurelia-framework';
export class MyComponent {
#bindable firstName;
}
i added this to the src folder.
my test code is
import {StageComponent} from 'aurelia-testing';
import {bootstrap} from 'aurelia-bootstrapper';
describe('MyComponent', () => {
let component;
beforeEach(() => {
component = StageComponent
.withResources('my-component')
.inView('<my-component first-name.bind="firstName"></my-component>')
.boundTo({ firstName: 'Bob' });
});
it('should render first name', done => {
component.create(bootstrap).then(() => {
const nameElement = document.querySelector('.firstName');
expect(nameElement.innerHTML).toBe('Bob');
done();
}).catch(e => { console.log(e.toString()) });
});
afterEach(() => {
component.dispose();
});
});
i jspm installed aurelia-bootstrapper and aurelia-testing to get it running.
im now getting the error
Error{stack: '(SystemJS) XHR error (404 Not Found) loading http://localhost:9876/base/my-component.js
so it looks like karma cant find my component. i checked the karma.config file and the jspm loadFiles: ['test/setup.js', 'test/unit/**/*.js'], looks correct.
has any one run into a similar issue?
solved the issue.
in karma.config.js file needed to change
serveFiles: ['src//.']
to
serveFiles: ['src//*.js', 'src/**/*.html']