Module Fedration :- While a new module is loaded onto the container whole layout (or the app is re-rendered) - webpack-5

Here is my system.js code for loading a component
export const loadComponent = (scope, module) => async () => {
// Initializes the share scope. This fills it with known provided modules from this build and all remotes
await __webpack_init_sharing__('modern');
const container = window[scope]; // or get the container somewhere else
// Initialize the container, it may provide shared modules
await container.init(__webpack_share_scopes__.default);
const factory = await window[scope].get(module);
const Module = factory();
return Module;
};
I have a sidebar and a header which re-renders every-time I navigate to a different page from the side bar.
Here is my layout.js code
import React, { useEffect, useState } from 'react';
import Header from '../header/header';
import Sidebar from '../sidebar/sidebar';
import './layout.scss';
const Layout = (props) => {
console.log(props, "props")
const [isIframe, setIsIframe] = useState(false);
const [branchIdFromUrl, setBranchIdFromUrl] = useState(null);
useEffect(() => {
const query = window?.location?.search;
const urlParams = new URLSearchParams(query);
const iframe = urlParams.get('iif');
const branch = urlParams.get('branchId');
if (iframe) {
setIsIframe(true);
}
if (branch) {
setBranchIdFromUrl(branch);
}
}, []);
return (
<div>
<Header isIframe={isIframe} branchIdFromUrl={branchIdFromUrl} />
<div className={isIframe ? 'main-wrapper-without-padding' : 'main-wrapper'}>
<div className="flex h-full">
<Sidebar />
<div className="flex-grow">
<div className="content-wrapper overflow-auto">
{/* <SearchBar/> */}
{/* <BreadCrumb/> */}
<div className="p-5">{props.children}</div>
</div>
</div>
</div>
</div>
</div>
);
};
export default Layout;
If any more information is needed let me know.

Related

How do I detect change Sveltekit state

I am trying to add a class to an element in one component (nav) when an animation in a different component (logo) ends. In my $lib/Logo.svelte file I have the following code:
<script>
import { onMount } from 'svelte';
import { isLogoAnimationEnded } from './stores';
onMount(() => {
const body = document.querySelector('body');
const h1 = document.querySelector('.name');
h1?.addEventListener('animationend', () => {
isLogoAnimationEnded.update((n) => (n = true));
console.log($isLogoAnimationEnded);
body?.classList.add('shake');
});
return () => {
h1?.removeEventListener('animationend', () => {
isLogoAnimationEnded.set(false);
body?.classList.remove('shake');
});
};
});
</script>
<div class="logo-wrapper">
<h1 class="name">Tim Smith</h1>
<p class="title">Full Stack Web Engineer</p>
</div>
<style>
...
</style>
My
store is defined in $lib/stores.js:
import { writable } from 'svelte/store';
export const isLogoAnimationEnded = writable(false);
What I am trying to do is listen for a change in isLogoAnimationEnded in $lib/Nav.svelte and add a class to nav when isLogoAnimationEnded becomes true.
<script lang="ts">
import { onMount } from 'svelte';
import { isLogoAnimationEnded } from './stores';
let nav;
onMount(() => {
nav = document.querySelector('nav');
console.log('nav', nav);
});
if ($isLogoAnimationEnded) {
nav?.classList.add('fly-down');
}
</script>
<div class="nav-wrapper">
<nav aria-label="Main">
<ul>
<li>About</li>
<li>Projects</li>
<li>Contact</li>
</ul>
</nav>
</div>
<style>
...
</style>
My current setup does not work. Please help.
The code below is only going to run once
if ($isLogoAnimationEnded) {
nav?.classList.add('fly-down');
}
So I would delete it and write the class attribute on nav element like this:
<nav class={$isLogoAnimationEnded ? "fly-down" : ""} aria-label="Main">
This also gets rid of the onMount, nav variable and querySelector

Best way to mock/stub vue-i18n translations in a vue3 component when using Vitest

I have started to replace Jest with Vitest for my unit test library in my Vue 3 App.
I am trying to write unit test for a component that uses the vue-i18n library to translate text within it but when I try to mount this component in my test file, it fails with the error:
ReferenceError: t is not defined
What is the proper way to stub/mock t from import { useI18n } from 'vue-i18n' when writing tests using the vitest library?
Note since upgrading from Vue2 to Vue3 this does not work:
const wrapper = shallowMount(MyComponent, {
global: {
mocks: {
$t: () => {}
}
}
})
Here is a list of some notable package versions:
"vue": "^3.2.31",
"vue-i18n": "^9.2.0-beta.14",
"vite": "^2.9.0",
"vitest": "^0.10.2"
Thanks!
import { createI18n } from 'vue-i18n';
describe('xxx', () => {
it('yyy', () => {
const i18n = createI18n({
messages: {
gb: {},
nl: {},
...
}
});
const wrapper = mount(YourComponent, {
global: {
plugins: [i18n]
}
});
}
})
I suppose you want to mock this globally, no need to put same code in every test suite.
// vitest.config.ts
import { mergeConfig } from 'vite';
import { defineConfig } from 'vitest/config';
import viteConfig from './vite.config';
export default defineConfig(
mergeConfig(viteConfig, { // extending app vite config
test: {
setupFiles: ['tests/unit.setup.ts'],
environment: 'jsdom',
}
})
);
// tests/unit.setup.ts
import { config } from "#vue/test-utils"
config.global.mocks = {
$t: tKey => tKey; // just return translation key
};
Panos Vakalopoulos’s answer worked for me.
And the code could be run globally.
See https://test-utils.vuejs.org/migration/#no-more-createlocalvue
// vite.config.ts
export default defineConfig(
// add config for test
test: {
environment: 'jsdom',
setupFiles: 'vitest.setup.ts',
}
);
// vitest.setup.ts'
import { config } from '#vue/test-utils'
import { createI18n } from 'vue-i18n'
const i18n = createI18n()
config.global.plugins = [i18n]
// YourComponent.vue
<div id="app">
<p>{{ t("message.hello") }}</p>
</div>
<script lang="ts" setup>
import { useI18n } from 'vue-i18n'
const { t } = useI18n()
</script>
// component_test.ts
describe('xxx', () => {
it('yyy', () => {
const wrapper = mount(YourComponent);
}
})
Note that if you use global config as $t, Luckylooke's answer would work.
// YourComponent.vue
<div id="app">
<p>{{ $t("message.hello") }}</p>
</div>
// tests/unit.setup.ts
import { config } from "#vue/test-utils"
config.global.mocks = {
$t: tKey => tKey; // just return translation key
};
I read this tutorial that teaches to mock vue-router, then I made a similar solution for vue-i18n and it worked.
Component (HelloWorld.vue)
<script setup>
import { useI18n } from "vue-i18n";
const { t } = useI18n();
</script>
<template>
<div class="greetings">
<h1>{{ t("commonsmessagehello") }}</h1>
<h2>{{ t("localhello") }}</h2>
<h2>{{ $t("message.success") }}</h2>
</div>
</template>
<i18n src="../commons/locales.json"></i18n>
<i18n>
{
"enUS": {
"localhello": "local helloooooo"
}
}
</i18n>
Test
import { describe, it, expect, vi } from "vitest";
import { mount, config } from "#vue/test-utils";
import { useI18n } from "vue-i18n";
import HelloWorld from "../HelloWorld.vue";
vi.mock("vue-i18n");
useI18n.mockReturnValue({
t: (tKey) => tKey,
});
config.global.mocks = {
$t: (tKey) => tKey,
};
describe("HelloWorld", () => {
it("renders properly", () => {
const wrapper = mount(HelloWorld, { });
expect(wrapper.text()).toContain("message.success");
});
});
How you can see, it worked for t and $t.
That's not the ideal way. Someday I'll try to figure out how to do it globally for every test.

How to filter elements using React, Graphql and Apollo with es6

I have a React project with a GraphQL using Apollo client. I am trying to figure out how to change the query result based on search text. I implemented query search in backend and its working perfectly.
But I dont know how to set up filter in React using that same query.
Despite there is tutotial on how to filter on https://www.howtographql.com/react-apollo/7-filtering-searching-the-list-of-links/, it doesnt use ES6 and I literaly dont know how to do it. Im stuck on this filter around 10 days.
I will show you my code.
App.js
import React from 'react';
import HeroesDota from './components/HeroesDota';
import Search from './components/HeroSearch'
import { ApolloProvider } from '#apollo/react-hooks';
import { ApolloClient } from "apollo-client";
import { InMemoryCache } from "apollo-cache-inmemory";
import { HttpLink } from "apollo-link-http";
const cache = new InMemoryCache();
const link = new HttpLink({
uri: "http://localhost:8000/graphql/"
});
const client = new ApolloClient({
cache,
link
});
const App = () => {
return (
<ApolloProvider client={client}>
<Search />
<HeroesDota />
</ApolloProvider>
)};
export default App;
HeroesDota.js (compoenent)
import React from 'react'
import gql from "graphql-tag";
import { useQuery } from '#apollo/react-hooks';
import '../index.css'
import styled from 'styled-components';
const Images = styled.img`
margin:0;
border: 3px solid #288eea;
display: inline;
width: 90px;
height: 50px;
`
const HEROES_DOTA2 = gql`
query {
heroes {
name
heroType
image
}
}
`;
const HeroesDota = () => {
const { loading, error, data } = useQuery(HEROES_DOTA2);
if (loading) return <p>Loading...</p>;
if (error) return <p>Error :(</p>;
return data.heroes.map(({name, heroType, image }) => (
<div className="row" key={Math.random() + 1}>
<div className="column">
<button className="button-hero"><Images className="hero_images" src= {`${image}`} alt={name}></Images></button>
<div className="hero_info">{name} - {heroType}</div>
</div>
</div>
));
}
export default HeroesDota;
HeroSearch.js (compoenent that doesnt work as I expected)
import React, { useState } from 'react'
import gql from "graphql-tag";
import { withApollo } from 'react-apollo'
import Hero from './HeroesDota'
import '../index.css'
const SEARCH_HEROES = gql`
query ($search: String) {
heroes (search: $search) {
id
name
}
}
`;
const Search = () => {
const [heroes, setHeroes] = useState([])
const [search, setSearch] = useState('')
const _executeSearch = async () => {
const { search } = search
const result = await this.props.client.query({
query: SEARCH_HEROES,
variables: { search },
})
const heroes = result.data.heroes.name
setHeroes({ heroes })
}
return (
<div>
<div>
Search
<input
type='text'
onChange={e => setSearch({ search: e.target.value })}
/>
<button onClick={() => _executeSearch()}>OK</button>
</div>
{heroes.map((hero, index) => (
<Hero key={hero.id} hero={hero} index={index} />
))}
</div>
)
}
export default withApollo(Search)
After U oress OK button to exectue search i get following error.
Unhandled Rejection (ReferenceError): Cannot access 'search' before initialization.
If I try to do something similar like I did in Component HeroesDota i still cant make it.
Does anyone know how to filter query in React using es6, not class based compoenent like they did on this tutorial.
Thanks
const Search = (props) => {
props.client.query()
...
}
or
const Search = ({ client }) => {
client.query()
...
}
Although I would also recommend you use the the new hooks syntax.

NuxtJS , Unit Test language picker with Jest and nuxt-i18n

I have a component that switch Language of a nuxtjs application using nuxt-i18n as follows
<template>
<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link langpicker">{{ $t("language_picker") }} </a>
<div class="navbar-dropdown is-hidden-mobile">
<div>
<nuxt-link
v-if="currentLanguage != 'en'"
class="navbar-item"
:to="switchLocalePath('en')"
>
<img src="~/static/flags/us.svg" class="flagIcon" /> English
</nuxt-link>
<nuxt-link
v-if="currentLanguage != 'el'"
class="navbar-item"
:to="switchLocalePath('el')"
>
<img src="~/static/flags/el.svg" class="flagIcon" /> Ελληνικά
</nuxt-link>
</div>
</div>
</div>
</template>
<script>
export default {
name: "LangPicker",
computed: {
currentLanguage() {
return this.$i18n.locale || "en";
}
}
};
</script>
I want to write a Unit Test that test the correct language switch on 'nuxt-link' click.
So far I have the following
import { mount, RouterLinkStub } from "#vue/test-utils";
import LangPicker from "#/components/layout/LangPicker";
describe("LangPicker with locale en", () => {
let cmp;
beforeEach(() => {
cmp = mount(LangPicker, {
mocks: {
$t: msg => msg,
$i18n: { locale: "en" },
switchLocalePath: msg => msg
},
stubs: {
NuxtLink: RouterLinkStub
}
});
});
it("Trigger language", () => {
const el = cmp.findAll(".navbar-item")
});
});
cmp.find(".navbar-item") return an empty object.
I don't know how I must set up to "trigger" the click event.
const el = cmp.findAll(".navbar-item")[1].trigger("click");
make sure your find selector is correct.
const comp = cmp.find(".navbar-item");
comp.trigger('click');
you can use chrome dev tools selector utility.
Refer this link for detailed information.

How to stop redux-form or React from changing htmlFor and id when creating Jest snapshots?

I've got a wizard form made with redux-forms v6 and it looks something like:
--
index.js - Holds page number in local state, is connected to application level state
PageOne - wrapped with reduxForm decorator (form: 'wizForm')
PageTwo - wrapped with reduxForm decorator (form: 'wizForm')
--
PageOne and PageTwo both contain additional components that render sections of the form (initial fields, vehicle information, driver information...), and each of those sections render their own components for each question in that section.
Since there's a lot of nested components and I want to test that PageOne and PageTwo call the props passed from index.js, I've resorted to using Enzyme's mount() function with a fake store. I want to MatchSnapshot() with Jest to compare whether index.js is rendering PageOne or PageTwo, after certain buttons are clicked to go back and forth from pages.
The problem is when I do create snapshots, other than creating a 16,000 line snapshot, the snapshot will NEVER match the previous one even if I don't change anything. I'm not sure if it's redux-form that's doing it or React, but the htmlFor and the id keep changing between snapshots, test after test after test.
We use css-modules too, but I don't think that's causing the problem, and we did configure Jest to work with css-modules too, modifying "moduleNameWrapper" to mock .css files. Does anyone know how to fix this or where I should look?
tests:
describe('<VehicleAddition />', () => {
let props;
beforeEach(() => {
props = {
...,
};
});
it('Renders initially', () => {
const component = shallow(<VehicleAddition {...props} />);
expect(toJson(component)).toMatchSnapshot();
});
it('Renders <PageTwo> when <PageOne> form is submitted', () => {
const component = shallow(<VehicleAddition {...props} />);
expect(toJson(component)).toMatchSnapshot();
component.find('ReduxForm') // reduxForm HOC wraps the <form> in a <ReduxForm> component
.first()
.simulate('submit');
expect(toJson(component)).toMatchSnapshot();
expect(component.state().page).toEqual(2);
});
it('PageTwoStuffs', () => {
// Render the form, click 'next', assert it's page two
// click 'previous'
jest.enableAutomock();
const store = createStore(
combineReducers({
route: jest.fn(() => Immutable.fromJS({})),
language: jest.fn(() => Immutable.fromJS({})),
global: jest.fn(() => Immutable.fromJS({})),
form: formReducer,
}),
Immutable.fromJS({}),
);
const component = mount(
<Provider store={store}>
<VehicleAddition {...props} />
</Provider>
);
// CAN'T check the state of <VehicleAddition /> because it can only be done on root component, says the error message.
expect(toJson(component)).toMatchSnapshot();
index.js:
export class VehicleAddition extends React.Component { // eslint-disable-line
constructor(props) {
super(props);
this.state = {
page: 1,
};
}
nextPage = () => {
this.setState({ page: this.state.page + 1 });
}
previousPage = () => {
this.setState({ page: this.state.page - 1 });
}
render() {
return (
<div>
{page === 1 &&
<PageOne
{...this.props}
/>
}
{page === 2 &&
<PageTwo
{...this.props}
/>
}
</div>
);
}
}
PageOne.js
class PageOne extends React.Component { // eslint-disable-line
render() {
const {
...
} = this.props;
return (
<form onSubmit={handleSubmit}>
<div>
<InitialFields
autoPolicies={autoPolicies}
changeField={this.changeField}
getFormValues={getFormValues}
policies={policies}
primary={primary}
/>
<VehicleBeingAddedFields
changeField={this.changeField}
getFormValues={getFormValues}
fetchVehMakes={fetchVehMakes}
fetchVehModels={fetchVehModels}
policies={policies}
vehMakes={vehMakes}
vehModels={vehModels}
/>
...
<div className="btn-group btn-group-float-right">
<button
type="submit"
onClick={this.handleClick}
disabled={pristine || submitting}
className="btn-primary"
>
Next
</button>
</div>
</form>
);
}
}
PageTwo.js:
class PageTwo extends React.Component { // eslint-disable-line
render() {
const {
...
} = this.props;
return (
<form onSubmit={handleSubmit}>
...
<div className="btn-group btn-group-float-right">
<button type="button" className="btn" onClick={previousPage}>Previous</button>{' '}
<button type="submit" disabled={pristine || submitting} className="btn-primary">Submit</button>
</div>
</form>
);
}
}
Example of the parts of the snapshot that constantly changes:
I solved it by passing a hardcoded id value from the test cases
import React from 'react';
import renderer from 'react-test-renderer';
import { reduxForm } from 'redux-form';
import { createStore } from 'redux';
import { Provider } from 'react-redux';
import { mount } from 'enzyme'
import TodoItem from './TodoItem';
import injectTapEventPlugin from 'react-tap-event-plugin';
function setup() {
const spy = jest.fn();
const store = createStore(() => ({}));
const Decorated = reduxForm({ form: 'testForm' })(TodoItem);
const props = {
remove: jest.fn(),
TodoItemReduxFormInitialName: "fullName",
snapshotTestId:"4"
}
const mockedComponent = <Provider store={store}>
<Decorated {...props} />
</Provider>;
const enzymeWrapper = mount(mockedComponent)
injectTapEventPlugin();
return {
props,
mockedComponent,
enzymeWrapper
}
}
describe('TodoItem Component', () => {
it('should render the snapshot', () => {
const {mockedComponent} = setup()
const tree = renderer.create(
mockedComponent
).toJSON();
expect(tree).toMatchSnapshot();
});
//not required as snapshot testing covers it
it('should render Number', () => {
const {enzymeWrapper} = setup()
const fieldProps = enzymeWrapper.find('Field').at(0).props();
expect(fieldProps.hintText).toEqual('Item Number');
expect(fieldProps.name).toEqual('fullName.itemNumber');
});
//not required as snapshot testing covers it
it('should render remove button', () => {
const {enzymeWrapper} = setup()
const button = enzymeWrapper.find('RaisedButton').at(0).props();
expect(button.label).toEqual("remove")
});
});