how do i run a test with jest/RTL on authcontext()
I am trying to test the process of my code when the user logs in correct information; however, i get stuck on an error that states that authContext is seen as undefined. Am i testing this correctly? How do i fix this error?
error
TypeError: Cannot read property 'setUser' of undefined
25 | const { isAuthenticated, user } = data;
26 | if (isAuthenticated) {
> 27 | authContext.setUser(user);
loginForm.test.js
test('user input correct login information', () => {
const { getByTestId, getByText } = render(<LoginForm />);
const resInfo = {username: 'Bpun1p'}
const resp = {isAuthenticated: true, user: resInfo}
AuthService.login.mockResolvedValue(resp)
fireEvent.change(getByTestId('Username'), {target: {value: "Bpun1p"}})
fireEvent.change(getByTestId('Password'), {target: {value: "Guy123su"}})
fireEvent.click(getByTestId('LoginBtn'));
});
loginForm.js
import React, { useContext, useState } from 'react';
import { useHistory } from 'react-router-dom';
import SocialSignUp from './SocialSignUp';
import { AuthContext } from '../../context/AuthContext';
import AuthService from '../../service/AuthService';
function LoginForm() {
const [username, setUsername] = useState({ username: '' });
const [isValidEntry, setValidEntry] = useState(true);
const authContext = useContext(AuthContext);
const history = useHistory();
const onChange = (event) => {
setUsername({ ...username, [event.target.name]: event.target.value });
};
const onSubmit = (event) => {
event.preventDefault();
if (username.username !== '') {
AuthService.login(username)
.then((data) => {
console.log(data);
const { isAuthenticated, user } = data;
if (isAuthenticated) {
authContext.setUser(user);
authContext.setIsAuthenticated(isAuthenticated);
history.push('/profile/global');
} else setValidEntry(false);
});
} else setValidEntry(false);
};
1 answer
-
answered 2020-11-25 01:42
IamMHC
in Test
<LoginForm/>
replace with<AuthContext.Provider> <LoginForm/><AuthContext.Provider>
and pass the required props for AuthContext.Provider for the run app
See also questions close to this topic
-
Deployment problems with React-Express App
I'm trying to deploy a MERN app (built with create react app) to Heroku, but whenever I try to access the URL, it returns with a 404 error.
During development I structured my project so that it runs on two different servers: client side on local host:3000, which proxies requests to express (at localhost:5000).
I've run
npm run build
, set up static middleware, and tried to configure my api calls/routes correctly, but it still isn't working. Any suggestions as to why, and how I can fix it? Details as follows:Project Structure
+client | +-build +-static +-css +-js +-media +-node_modules +-public +-src | +-components +-App.js +-index.js //server +-models +-node-modules +-package-lock.json +-package.json +-server.js
Proxy (in package.json):
"proxy": "http://localhost:5000"
Server config:
const port = process.env.PORT || 5000; app.listen(port, () => console.log(`Listening on port ${port}`)); //Middleware if (process.env.NODE_ENV === 'production') { app.use(express.static(path.join(__dirname, '../client/build'))); } app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: true })); app.use(express.urlencoded()) app.use(cors())
Here's how I;ve structured my APIs. Note: I've removed the 'localhost:5000' from the URL of my axios requests:
API call from React component:
useEffect(() => { axios.get('/api/all-reviews') .then(review => { setReviews(review.data) }) .catch(err => { console.log(err) }) },[])
Corresponding express route
app.get('/api/all-reviews', (req,res) => { Review.find() .then((result) => { res.send(result) }) .catch(err => { console.log(err) }) })
-
How with Material UI to align input fields and buttons in the correct way in a dialog
In my React app, I have to align correctly the items in a dialog of MUI.
As per the screenshot, I have an issue to align the input fields Date and time. They should be aligned in the center and the Date input should start aligned with the title text above and the Time input should align with the button on the far right Save and close.
The second main issue is the buttons, I need to position Cancel and Save and close on the right and on the same row but on the left side, the button Remove call.
I have an issue making these alignments.
The code of the dialog
const useStyles = makeStyles(theme => ({ root: { margin: 0, padding: theme.spacing(1), '& .MuiFilledInput-root': { borderRadius: 0, }, }, dialogTitle: { marginTop: theme.spacing(2), }, container: { margin: theme.spacing(1), width: '80%', }, textField: { marginLeft: theme.spacing(1), marginRight: theme.spacing(1), }, button: { marginRight: theme.spacing(1), height: 40, }, paper: { overflowY: 'unset', }, closeButton: { position: 'absolute', left: '93%', top: '3%', color: 'gray', }, buttonRight: { justifyContent: 'flex-end', }, })); <Dialog open={open} fullWidth maxWidth="md" classes={{ paper: classes.paper }} > <DialogTitle className={classes.dialogTitle}> <Typography variant="h1" gutterBottom> Schedule a call </Typography> <InfoCallMessage call={appointment} /> </DialogTitle> {!loading ? ( <> <DialogContent className={classes.root}> <Grid className={classes.container} container justify="flex-end" alignItems="center" spacing={1} > <Grid item xs={8}> <MuiPickersUtilsProvider utils={LuxonUtils}> <DatePicker className={classes.input} disableToolbar variant="inline" label="Date" format="cccc, LLLL dd" helperText="" value={date} margin="normal" onChange={newDate => { handleDateOnChange({ newDate }); }} inputVariant="filled" fullWidth minDate={new Date()} /> </MuiPickersUtilsProvider> </Grid> <Grid item xs={4}> <TextField key={time} id="time" label="Time" type="time" defaultValue={time} className={classes.textField} InputLabelProps={{ shrink: true, }} variant="filled" margin="normal" onChange={e => { const { value } = e.target; setTime(value); }} fullWidth /> </Grid> <ErrorDateTimeIsAfter /> </Grid> </DialogContent> <DialogActions className={classes.buttonRight}> <IconButton className={classes.closeButton} onClick={() => closeDialog()} > <CloseIcon /> </IconButton> <Grid justify="space-between" container spacing={1}> <Grid item> <Button color="secondary" variant="contained" onClick={() => closeDialog()} className={classes.button} > Remove call </Button> </Grid> <Grid item> <Button color="primary" variant="outlined" onClick={() => closeDialog()} className={classes.button} > Cancel </Button> </Grid> <Grid item> <Button color="primary" variant="contained" onClick={() => handelSave()} className={classes.button} disabled={!isAfter(parseISO(`${date}T${time}`), new Date())} > Save and Close </Button> </Grid> </Grid> </DialogActions> </> ) : ( <Loading /> )} </Dialog>
-
transition animation not working in tailwindcss/react
I am a newbie learning React & Tailwind. I have a
Navbar
component which I have written like following,const Navbar = () => { const [showModal, setShowModal] = useState(false); return ( <> <nav className="flex justify-between items-center h-16 bg-white text-black relative shadow-md font-quicksand"> <Link to='/' className='pl-8'>Project</Link> <div className="px-4 cursor-pointer md:hidden"> {/* <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"></path> </svg> */} <button type="button" className="bg-white rounded-md p-2 inline-flex items-center justify-center text-gray-400 hover:text-gray-500 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-indigo-500" id="main-menu" aria-haspopup="true" onClick={() => setShowModal(true)} > <span className="sr-only">Open main menu</span> <svg className="h-6 w-6" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" /> </svg> </button> </div> <div className="pr-8 md:block hidden"> <Link to='/' className='p-4 font-bold'>Home</Link> <Link to='/menu' className='p-4 font-bold'>Menu</Link> <Link to='/about' className='p-4 font-bold'>About</Link> <Link to='/contact' className='p-4 font-bold'>Contact</Link> <Link to='/login' className="p-4 font-bold text-indigo-600 hover:text-indigo-500" role="menuitem">Log in</Link> <Link to='/register' className="p-4 font-bold text-indigo-600 hover:text-indigo-500" role="menuitem">Register</Link> </div> </nav> {showModal ? ( <div className="absolute top-0 inset-x-0 p-2 transition duration-500 ease-in-out transform origin-top-right md:hidden"> <div className="rounded-lg shadow-md bg-white ring-1 ring-black ring-opacity-5 overflow-hidden"> <div className="px-5 pt-4 flex items-center justify-between"> <div className="-mr-2"> <button type="button" className="bg-white rounded-md p-2 inline-flex items-center justify-center text-gray-400 hover:text-gray-500 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-indigo-500" onClick={() => setShowModal(false)} > <span className="sr-only">Close main menu</span> <svg className="h-6 w-6" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" /> </svg> </button> </div> </div> <div role="menu" aria-orientation="vertical" aria-labelledby="main-menu"> <div className="px-2 pt-2 pb-3 space-y-1" role="none"> <Link to='/' className="block px-3 py-2 rounded-md text-base font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-50" role="menuitem">Home</Link> <Link to='/menu' className="block px-3 py-2 rounded-md text-base font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-50" role="menuitem">Menu</Link> <Link to='/about' className="block px-3 py-2 rounded-md text-base font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-50" role="menuitem">About</Link> <Link to='/contact' className="block px-3 py-2 rounded-md text-base font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-50" role="menuitem">Contact</Link> </div> <div role="none"> <Link to='/login' className="block w-full px-5 py-3 text-center font-medium text-indigo-600 bg-gray-50 hover:bg-gray-100" role="menuitem"> Log in </Link> </div> <div role="none"> <Link to='/register' className="block w-full px-5 py-3 text-center font-medium text-indigo-600 bg-gray-50 hover:bg-gray-100" role="menuitem"> Register </Link> </div> </div> </div> </div> ) : null} </> ) }
As you can see that when the screen got smaller the hamburger menu button will appear and when I click on that button it opens a modal with all the header components (The modal code copied from tailwind official components Hero components).
The problem is when that modal appears tailwind transition animation suppose to happen but it is not working. What am i doing wrong here?? Do i have to use the react hook
useEffect
somehow to make this work??Any kind of answer would be appreciated.
-
Wordpress popup if login failed
Well I'm preparing for a project in my study. so please help me
I have a page with a button to login, user click the button and a popup appears to log in or create an account. It works perfectly with only one mistake, If user fill the form with a wrong password for exemple the popup close and he didn't login, he must click again in the button to see the error in form. I need to make a redirection that if login failed the page refresh and the popup with the wrong appears automatically. Thanks all
-
Nuxt Authentication with @nuxt/auth - /api/sessions not found
i'm already trying for hours to implement @nuxt/auth https://auth.nuxtjs.org/
I'm following this tutorial: https://www.youtube.com/watch?v=zzUpO8tXoaw&t=978s&ab_channel=VueScreencasts
When I try to make an API call, it cannot find the route.
POST http://localhost:3000/api/sessions 404 (Not Found)
I'm using
"nuxt": "^2.14.12" "@nuxtjs/auth": "^4.9.1", "@nuxtjs/axios": "^5.1.0",
Here is my complete nuxt.config.js
export default { /* ** Nuxt rendering mode ** See https://nuxtjs.org/api/configuration-mode */ mode: 'universal', /* ** Nuxt target ** See https://nuxtjs.org/api/configuration-target */ target: 'server', /* ** Headers of the page ** See https://nuxtjs.org/api/configuration-head */ head: { title: process.env.npm_package_name || '', meta: [ { charset: 'utf-8' }, { name: 'viewport', content: 'width=device-width, initial-scale=1' }, { hid: 'description', name: 'description', content: process.env.npm_package_description || '' } ], link: [ { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' } ] }, /* ** Global CSS */ css: [ '@/assets/scss/main.scss' ], /* ** Plugins to load before mounting the App ** https://nuxtjs.org/guide/plugins */ plugins: [ ], /* ** Auto import components ** See https://nuxtjs.org/api/configuration-components */ components: true, /* ** Nuxt.js dev-modules */ buildModules: [ ], /* ** Nuxt.js modules */ modules: [ // Doc: https://bootstrap-vue.js.org 'bootstrap-vue/nuxt', // Doc: https://axios.nuxtjs.org/usage '@nuxtjs/axios', '@nuxtjs/auth' ], bootstrapVue: { bootstrapCSS: false, bootstrapVueCSS: false, }, /* ** Axios module configuration ** See https://axios.nuxtjs.org/options */ axios: { baseURL: 'http://localhost:3000/api', }, auth: { strategies: { local: { endpoints: { login: { url: '/sessions', method: 'post', propertyName: 'token' }, logout: { url: 'api/auth/logout', method: 'post' }, user: { url: '/sessions/user', method: 'get' } }, tokenType: '', } } }, /* ** Build configuration ** See https://nuxtjs.org/api/configuration-build/ */ build: { } }
within my
pages/admin.vue
methods: { async login() { try { let response = await this.$auth.loginWith('local', { data: { username: this.username, password: this.password, } }) console.log(response) } catch (err) { console.log(err) } } },
What am I missing? I appreciate any help
-
Can't Logout when hold a button in Flask-JWT-Extended template
I create an application where are templates and resources(Flask-restful) Every time when I click on Logout from my HomePage it redirect me to Login form, but didn't clear a previous token, so I can visit Homepage without any errors
class HomePage(Resource): @jwt_required def get(self): jti = get_raw_jwt()['jti'] if is_jti_blacklisted(jti): return make_response(redirect(url_for('loginuser'))) else: username = get_jwt_identity() print(jsonify({'hello': 'from {}'.format(username)})) return make_response(render_template('home.html'))
<h1> HOME PAGE </h1> <p><a href="{{ url_for('userlogoutaccess') }}">Logout</a></p>
If I debug It and put a point to any lines under class UserLogoutAccess nothing happened, I can't understand why.
class UserLogoutAccess(Resource): @jwt_required def post(self): jti = get_raw_jwt()['jti'] revoked_token = RevokedTokenModel(jti=jti) revoked_token.add() resp = make_response(redirect(url_for('loginuser'))) unset_jwt_cookies(resp) return resp, 200 def get(self): return make_response(redirect(url_for('loginuser')))
-
jest mocking a response to handle response.blob()
I'm trying to test the below code which makes an api call to download a file blob from the reponse by calling
response.blob()
. However I'm not sure how I can mock this and the response so that I can test a successful response and validate that thedownloadFile()
function is called. The key part I'm not sure about is how to mock a function's returned value to be an object that you later call a method on (.blob())code to test:
...... const response = await apiCall<Response>(dispatch, request, false); try { const file = await response.blob(); const fileUrl = window.URL.createObjectURL(file); downloadFile(fileUrl, 'filename.csv'); } catch { throw response; }
test
describe('downloadsAFile', () => { it('downloads successfully', async () => { global.URL.createObjectURL = jest.fn(); expect(downloadFile).toBeCalled(); });
-
Test worker thread with mocks
My Node application uses AWS SDK, and in order to mock it locally I am using Jest's manual mocks. Basically I am placing in
__mocks__
folder barebone mock of AWS SDK that simulates methods I use - and during Jest tests this "AWS-SDK" is being called by the main code.This works fine for the regular code flow. But when I invoke a worker thread (I am using sync-thread library but this is true for regular worker usage) - code inside of the worker tries to call real AWS-SDK when running Jest tests.
Is there a way to make it use mocked one as well? Also environmental variables set in the worker don't persist for the caller thread - is this by design or could they be set this way?
-
NestJS: Unit Test Joi Validation
I'am new using Node and Nest framework, and I have a problem when testing modules that import a Custom Config Module that uses Joi to validate env vars:
yarn test Test suite failed to run Config validation error: "APP_PORT" is required
app-config.module.ts
@Module({ imports: [ ConfigModule.forRoot({ expandVariables: true, load: [configuration], validationSchema: Joi.object({ APP_PORT: Joi.number().required() }), }), ], providers: [AppConfigService], exports: [AppConfigService], }) export class AppConfigModule { }
app.config.ts
import { registerAs } from '@nestjs/config'; export default registerAs('app', () => ({ env: process.env.NODE_ENV, port: process.env.APP_PORT || 3000 ... }));
invoice.service.spec.ts
describe('InvoiceService', () => { let service: InvoiceService; beforeEach(async () => { const module: TestingModule = await Test.createTestingModule({ imports: [ ConfigModule.forRoot({ load: [configuration], ignoreEnvFile: true, }), AppConfigModule ], providers: [ InvoiceService, .... ], }).compile(); service = module.get<InvoiceService>(InvoiceService); }); it('should be defined', () => { expect(service).toBeDefined(); }); });
I use env file to deploy locally, and I only set up
ignoreEnvFile: true
in test class because env file is ignore from github repo, and project integrate github actions that run unit test.How is the best way to solved this problem? I would not like add env file to repo. Exist any way to disable/fake/mock Joi validation method. I saw some examples using setupFiles but I'm not sure if it's a good practice.
-
Azure AD callback URL is not getting hit every time
It gets hit only when I clear site data and then try to login with Azure AD. Tried setting cache to no-store for all the requests but still not working.
-
How can I develop custom passport-local authentication strategy for use with my REST API
I'm using the Express framework to create a REST API that will be used to ingest client data. My API will require the formatting below. I would like to create an authentication strategy with passport that can be used to parse out the login token email and password. Request example below.
{ "security": { "loginToken": { "email": "test@email.com", "password": "testpassword" }, "accessToken": { "apiAccessKey": "api_access_key_here" } }, "data": { "partners": [ { "partner_id":"testvalue1", "tech":"testvalue2" }, { "partner_id":"testvalue3", "tech":"testvalue4" } ] } }
The standard passport.authenticate function doesn't seem to work for this because "email" and "password" are nested in the JSON request. Can I somehow specify in the local authentication strategy
email: req.body.security.loginToken.email
? Any help here would be greatly appreciated. -
NestJS custom PassportStrategy not registered when shared through library
I've been tasked with isolating our NestJS authentication module into a separate shared library, in order for it to be reused between multiple NestJS projects. Each project lives in each own repository and the shared library is imported as an npm package. I'm using NestJS' passport module for the authentication (using jwt tokens) and have basically just followed the official documentation on how to implement it.
I've followed the pattern of other NestJS community packages, and so far I've moved most of the authentication code over and made sure it could compile and run.
Now, I've come across an issue. The application no longer recognizes the custom jwt passport strategy, after I moved it over to the library and I have no idea why. I just get the exception:
Unknown authentication strategy "jwt"
Example:
This is the custom passport strategy and the AuthModule (the real version is more complex, but this is a minimal reproduceable example). The code is exactly the same in both the "parent"-project and the new library-project.
import { Injectable, Module } from '@nestjs/common'; import { PassportStrategy } from '@nestjs/passport'; import { Strategy } from 'passport-custom'; @Injectable() export class CustomStrategy extends PassportStrategy(Strategy, 'custom') { async validate(request: Request): Promise<any> { console.log('Custom validation', request); return true; } } @Module({}) export class AuthModule { static forRoot() { return { module: AuthModule, providers: [CustomStrategy], exports: [CustomStrategy], }; } }
This is how I register it in the NestJS application:
import { Module } from '@nestjs/common'; import { PassportModule } from '@nestjs/passport'; import { AuthModule } from '@my-org/common'; // Library version // import { AuthModule } from './auth/AuthModule'; // Local version @Module({ imports: [ AuthModule.forRoot(), PassportModule.register({ defaultStrategy: 'custom' }) ] }) export class CommonModule {} export class CustomAuthGuard extends AuthGuard('custom') {}
When the AuthModule is refererenced from within the same NestJS project, everything runs and I get the
Custom validation
console message.When the AuthModule is imported from my npm library, I get the
Unknown authentication strategy "custom"
exception from passport, whenever I make a request.The code on both sides is exactly the same. The usage of the module is exactly the same, regardless of where the module comes from. The shared library is set up using the same pattern as official NestJS packages, such as @nestjs/common and @nestjs/cqrs. Any other registered services exported by the library works as intended (I can include another minimal example to show this if requested).
What am I missing? How can I share my custom NestJS PassportStrategy using a separate npm package?
I've spent half my workday trying to solve this issue, and so far I think it might have something to do with which passport instance the strategy is registered with, but I don't know how to test this - or, if that is even the case, how to solve it.
-
reach-router navigate function not working with react-testing-library
I cannot get navigate to work in my unit tests when changing the search path. I was able to reproduce the issue in the isolated test below.
Why is the history.location.search not updating after the button click? The final expect should be passing, but fails.
import { createHistory, createMemorySource, LocationProvider, navigate } from "@reach/router" import { render, waitFor } from "@testing-library/react" import userEvent from "@testing-library/user-event" import React from 'react' test('Can us search path', async () => { const history = createHistory(createMemorySource('/')) const page = render( <LocationProvider history={history}> <div> <button onClick={() => navigate('/?searchString=abcde')}>navigateButton</button> </div>) </LocationProvider> ) expect(history.location.search).toEqual('') userEvent.click(page.getByText('navigateButton')) //click button to call navigate await waitFor(() => expect(history.location.search).toEqual('searchString=abcde')) //FAILS but Should PASS })
dependencies
"@testing-library/react": "^11.2.3", "@testing-library/user-event": "^12.6.0", "@testing-library/jest-dom": "^5.11.9", "react": "^17.0.1", "react-dom": "^17.0.1", "@reach/router": "^1.3.4",
-
getByText doesn't find the element
I want to see if at least part of text is rendered..
<li> Click here <a id="myLink" className="xxxxx" target="_blank" rel="noreferrer" href="https://www.aaa.com" > to open xxx. </a> </li>
and test fails with:
xxxxxx.getByText('Click here')
but works fine if 'Click here' is only the text of that
- is there a method to do partial search?
-
Test input without label with React Testing Library
I use react-testing-library in my application. Normally, to check if the input is in the form, we use getByLabelText. For example:
getByLabelText(/name/i)
But what if my input does not have any label? This is because of the design (UI) so I cannot have a label for the input. How can I check if that input exists in the form?