0
 While adding test for am facing this particular issue can someone please help me to resolve this issue , just want to know how to set queryclient inside register page it self

Register.jsx ---Main page which is user registration trying to dom testing for this

   /* eslint-disable no-console */
import React, { useState, useEffect } from 'react';
import { Form, Input, Button, Checkbox, Divider } from 'antd';
import {
  UserOutlined,
  LockOutlined,
  MailOutlined,
} from '@ant-design/icons';
import { Link, Redirect } from 'react-router-dom';
import { useMutation } from 'react-query';
import { withTranslation } from 'react-i18next';

import { func } from 'prop-types';
import { registerUser } from '../../api/auth.api';

const Register = ({ t }) => {
  const [form] = Form.useForm();
  const [isMailInUse, setIsMailInUse] = useState(false);
  const {
    mutate,
    isSuccess,
    isError,
    isLoading,
    error,
  } = useMutation(registerUser);

  useEffect(() => {
    if (isError && error.response.status === 409) {
      setIsMailInUse(true);
      form.validateFields();
    }
  }, [isError, error, form]);

  const onFinish = (inputs) => {
    // console.log('Received values of form: ', inputs);
    mutate(inputs);
  };

  if (isSuccess) {
    return <Redirect to="/Dashboard" />;
  }

  return (
    <Form
      form={form}
      name="normal_login"
      className="login-form"
      initialValues={{
        remember: true,
      }}
      onFinish={onFinish}
    >
      <Form.Item
        name="fullname"
        data-testid="fullname"
        rules={[
          {
            required: true,
            message: t('form_errors.enter_full_name'),
          },
          {
            min: 4,
            message: t('form_errors.name_atleast_four_chars'),
          },
          {
            max: 20,
            message: t('form_errors.name_max_twenty_chars'),
          },
          {
            pattern: new RegExp(
              /^[A-Za-z\s]{1,}[.]{0,1}[A-Za-z\s]{0,}$/,
            ),
            message: t('form_errors.valid_name'),
          },
        ]}
      >
        <Input
          type="text"
          data-testid="username"
          prefix={<UserOutlined className="site-form-item-icon" />}
          placeholder={t('name')}
        />
      </Form.Item>
      <Form.Item
        name="email"
        rules={[
          {
            required: true,
            message: t('form_errors.email_required'),
          },
          {
            pattern: new RegExp(
              /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/,
            ),
            message: t('form_errors.valid_email_id'),
          },
          {
            validator: () =>
              !isMailInUse
                ? Promise.resolve()
                : Promise.reject(new Error(t('errors.email_in_use'))),
          },
        ]}
      >
        <Input
          type="email"
          onChange={() =>
            isMailInUse ? setIsMailInUse(false) : null
          }
          prefix={<MailOutlined className="site-form-item-icon" />}
          placeholder={t('email')}
        />
      </Form.Item>
      <Form.Item
        name="password"
        rules={[
          {
            required: true,
            message: t('form_errors.password_not_found'),
          },
          {
            min: 8,
            message: t('form_errors.password_min_eight_chars'),
          },
        ]}
        hasFeedback
      >
        <Input.Password
          prefix={<LockOutlined className="site-form-item-icon" />}
          type="password"
          autoComplete="new-password"
          placeholder={t('password')}
        />
      </Form.Item>
      <Form.Item
        name="confirmpassword"
        dependencies={['password']}
        rules={[
          {
            required: true,
            message: t('form_errors.password_confirmation'),
          },
          ({ getFieldValue }) => ({
            validator(_, value) {
              if (!value || getFieldValue('password') === value) {
                return Promise.resolve();
              }
              return Promise.reject(
                new Error(t('errors.passwords_do_not_match')),
              );
            },
          }),
        ]}
        hasFeedback
      >
        <Input.Password
          prefix={<LockOutlined className="site-form-item-icon" />}
          type="password"
          autoComplete="new-password"
          placeholder={t('tasks.confirm_password')}
        />
      </Form.Item>
      <Form.Item>
        <Form.Item name="remember" valuePropName="checked" noStyle>
          <Checkbox>{t('tasks.remember_me')}</Checkbox>
        </Form.Item>

        <Link
          className="login-form-forgot"
          style={{ float: 'right' }}
          to="#/something"
        >
          {t('forgot_password')}
        </Link>
      </Form.Item>
      <Form.Item>
        <Button
          type="primary"
          loading={isLoading}
          htmlType="submit"
          className="login-form-button"
        >
          {t('tasks.register')}
        </Button>
        {'\n'}
        Or
        {'\n'}
        <Button
          type="ghost"
          htmlType="submit"
          className="login-form-button"
          onClick={() =>
            window.open(
              'http://api.realdev.in/oauth/redirect/github',
              '_self',
            )
          }
        >
          {t('tasks.login_with_github')}
        </Button>
        <Divider plain>OR</Divider>

            <Link to="/login"> {t('tasks.login_now')}</Link>
          </Form.Item>
        </Form>
      );
    };
    
    Register.propTypes = {
      t: func.isRequired,
    };
    
    export default withTranslation()(Register);

-- Main component which get loaded on page render ,here I have added queryclient for reactquery usage App.jsx

     import React, { useEffect } from 'react';
import { withTranslation } from 'react-i18next';
import { func, shape } from 'prop-types';
import { Row, Col, Typography, Tabs } from 'antd';
import '../css/form.css';
import {
  BrowserRouter as Router,
  Switch,
  Route,
} from 'react-router-dom';

import { Helmet } from 'react-helmet';
import { QueryClientProvider, QueryClient } from 'react-query';
import { ReactQueryDevtools } from 'react-query/devtools';
import Login from './Authentication/Login';
import Register from './Authentication/Register';
import OAuth from './Authentication/OAuth';
import GithubAuth from './Authentication/GithubAuth';
import Dashboard from './Authentication/Dashboard';
import Error from './Authentication/Error';

const { TabPane } = Tabs;
// import StoreDemo from './StoreDemo';
//
const queryClient = new QueryClient();

const App = ({ t, i18n }) => {
  useEffect(() => {
    i18n.changeLanguage('en');
  }, [i18n]);
  const { Text, Title } = Typography;

  return (
    <>
      <QueryClientProvider client={queryClient}>
        <Router>
          <Switch>
            <Route path="/oauth">
              <OAuth />
            </Route>

            <Route path="/projects">
              <h2>Projects</h2>
            </Route>

            <Route path="/Dashboard">
              <Dashboard />
            </Route>

            <Route path="/Error">
              <Error />
            </Route>

            <Route
              path="/:route"
              render={({ match, history }) => {
                if (
                  match.params.route === 'login' ||
                  match.params.route === 'register'
                ) {
                  return (
                    <>
                      <div className="form--wrapper">
                        <Row>
                          <Col span={24} offset={0}>
                            <Title className="site--logo">
                              {t('easy_collab')}
                            </Title>
                            <div className="form--container">
                              <Title level={3}>
                                {t('tasks.login_to_easycollab')}
                              </Title>
                              <Text type="secondary">
                                {t('tasks.continue_with_email')}
                              </Text>
                              <br />
                              <br />
                              <Switch>
                                <>
                                  <Tabs
                                    activeKey={match.params.route}
                                    onChange={(route) => {
                                      history.push(`/${route}`);
                                    }}
                                  >
                                    <TabPane tab="Login" key="login">
                                      <Helmet>
                                        <title>
                                          {t('tasks.login')} •{' '}
                                          {t('easy_collab')}
                                        </title>
                                      </Helmet>
                                      <Login />
                                    </TabPane>
                                    <TabPane
                                      tab="Register"
                                      key="register"
                                    >
                                      <Helmet>
                                        <title>
                                          {t('tasks.register')} •{' '}
                                          {t('easy_collab')}
                                        </title>
                                      </Helmet>
                                      <Register />
                                    </TabPane>
                                  </Tabs>
                                </>
                              </Switch>
                            </div>
                          </Col>
                        </Row>
                      </div>
                    </>
                  );
                }
                return null;
              }}
            />
            <Route path="/login/github" exact>
              <GithubAuth />
            </Route>

            <Route path="/" exact>
              <Helmet>
                <title />
                {t('home')} • {t('easy_collab')}
              </Helmet>
              {t('errors.unauthorized_access')}
            </Route>
          </Switch>
        </Router>
        <ReactQueryDevtools />
      </QueryClientProvider>
    </>
  );
};

App.propTypes = {
  t: func.isRequired,
  i18n: shape({ changeLanguage: func }).isRequired,
};

export default withTranslation()(App);

Register.test.jsx

    import React from 'react';
import {
  render,
  fireEvent,
  findByText,
} from '@testing-library/react';
import { expect } from 'chai';

import '../i18n/index';
import Register from '../components/Authentication/Register';
import App from '../components/App';

describe('App', () => {
  it('renders App component', async () => {
    const { getByTestId, container } = render(<Register />);
    const usernameEl = getByTestId('username');
    // const nameEl = getByTestId('fullname');
    fireEvent.change(usernameEl, {
      target: {
        value: 'po',
      },
    });
    expect(
      await findByText(
        container,
        'Name must be atleast 4 characters',
      ),
    ).toBeVisible();
  });
});

Error facing

          Browser logs:
      Error: No QueryClient set, use QueryClientProvider to set one
        at useQueryClient (_snowpack\pkg\common\QueryClientProvider-dd42f785.js:27:11)
        at useMutation (_snowpack\pkg\react-query.js:3092:21)
        at Register (dist\components\Authentication\Register.js:22:7)
        at renderWithHooks (_snowpack\pkg\common\index-163c0f63.js:16160:18)
        at mountIndeterminateComponent (_snowpack\pkg\common\index-163c0f63.js:18986:13)
        at beginWork (_snowpack\pkg\common\index-163c0f63.js:20224:16)
        at HTMLUnknownElement.callCallback (_snowpack\pkg\common\index-163c0f63.js:5123:14)
        at Object.invokeGuardedCallbackDev (_snowpack\pkg\common\index-163c0f63.js:5172:16)
        at invokeGuardedCallback (_snowpack\pkg\common\index-163c0f63.js:5234:31)
        at beginWork$1 (_snowpack\pkg\common\index-163c0f63.js:25128:7)
      Error: No QueryClient set, use QueryClientProvider to set one
        at useQueryClient (_snowpack\pkg\common\QueryClientProvider-dd42f785.js:27:11)
        at useMutation (_snowpack\pkg\react-query.js:3092:21)
        at Register (dist\components\Authentication\Register.js:22:7)
        at renderWithHooks (_snowpack\pkg\common\index-163c0f63.js:16160:18)
        at mountIndeterminateComponent (_snowpack\pkg\common\index-163c0f63.js:18986:13)
        at beginWork (_snowpack\pkg\common\index-163c0f63.js:20224:16)
        at HTMLUnknownElement.callCallback (_snowpack\pkg\common\index-163c0f63.js:5123:14)
        at Object.invokeGuardedCallbackDev (_snowpack\pkg\common\index-163c0f63.js:5172:16)
        at invokeGuardedCallback (_snowpack\pkg\common\index-163c0f63.js:5234:31)
        at beginWork$1 (_snowpack\pkg\common\index-163c0f63.js:25128:7)
      The above error occurred in the <Register> component:

          at Register (http://localhost:8000/dist/components/Authentication/Register.js:13:20)
          at withI18nextTranslation(Register) (http://localhost:8000/_snowpack/pkg/react-i18next.js:918:31)

      Consider adding an error boundary to your tree to customize error handling behavior.
      Visit https://reactjs.org/link/error-boundaries to learn more about error boundaries.
      Error: done() called multiple times in test <App renders App component>; in addition, done() received error: Error: No QueryClient set, use QueryClientProvider to set one
        at createMultipleDoneError (..\..\D:\Opensource\easy-collab-frontend\node_modules\@web\test-runner-mocha\dist\autorun.js:1:242101)
        at ..\..\D:\Opensource\easy-collab-frontend\node_modules\@web\test-runner-mocha\dist\autorun.js:1:254722
        at a (..\..\D:\Opensource\easy-collab-frontend\node_modules\@web\test-runner-mocha\dist\autorun.js:1:254732)
        at ..\..\D:\Opensource\easy-collab-frontend\node_modules\@web\test-runner-mocha\dist\autorun.js:1:255788

 ❌ App > renders App component
      Error: Uncaught Error: No QueryClient set, use QueryClientProvider to set one (http://localhost:8000/_snowpack/pkg/common/QueryClientProvider-dd42f785.js:27)
        at Object.invokeGuardedCallbackDev (_snowpack\pkg\common\index-163c0f63.js:5172:16)
        at invokeGuardedCallback (_snowpack\pkg\common\index-163c0f63.js:5234:31)
        at beginWork$1 (_snowpack\pkg\common\index-163c0f63.js:25128:7)
        at performUnitOfWork (_snowpack\pkg\common\index-163c0f63.js:23943:12)
        at workLoopSync (_snowpack\pkg\common\index-163c0f63.js:23871:5)
        at renderRootSync (_snowpack\pkg\common\index-163c0f63.js:23834:7)
        at performSyncWorkOnRoot (_snowpack\pkg\common\index-163c0f63.js:23457:18)
        at scheduleUpdateOnFiber (_snowpack\pkg\common\index-163c0f63.js:23045:7)
        at updateContainer (_snowpack\pkg\common\index-163c0f63.js:26646:3)

Chrome: |██████████████████████████████| 2/2 test files | 1 passed, 1 failed

Code coverage: 48.42 %
View full coverage report at coverage\lcov-report\index.html

Finished running tests in 19.1s with 1 failed tests.

Trying get resolve this issue am getting error like this, if anyone faced or can help me with this please answer to my query

1

1 Answer 1

1

From the error, you're missing the QueryProvider.

  1. Create a new client. It's useful to have set it not to retry:
const cleanClient = new QueryClient(
  {
    defaultOptions: {
      queries: {
        retry: false,
      },
    },
  });
  1. Create a a wrapper component:
const QueryProviderWrapper = ({ children }: { children: ReactElement}): ReactElement<QueryClientProviderProps> => {
  return (
      <QueryClientProvider client={client}>{children}</QueryClientProvider>
  );
};
  1. Modify your render:
const { getByTestId, container } = render(
  <QueryProviderWrapper client={cleanClient}>
    <Register />
  </QueryProviderWrapper>
);
  1. Depending on your tests, you may want to clear that client; this is the example for it:
afterEach(() => {
    cleanClient.clear();
  });
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.