简体   繁体   中英

antd component testing using react testing library and jest

I got an assignment to do component testing on a react page created by another developer in the team. the Frontend dev here uses UI kit from antd and redux for state management. For now I'm just making sure the page renders successfully, but they want me to test the functionality. Is there any proper way to do that? thanks in advance

To be honest, I still struggle to get the component inside the page, I try to use data-testid attribute but if it is wrapped by another component it can't be detected. so below is my Page Component and Test file.

FormAgMasuk.View.js <--- Component to test

 const FormAgMasukView = ({ onClose, onFinish, t, regId, penerima_level, retensi, native, noAgenda, arsipSurat, suratArsip, syncedAdmin, syncedReferensi, syncedNo, form, formInitialValues, rowSelection, visible, visibleRefForm, dataJenis, dataKontak, dataKelas, dataPrioritas, dataMedia, dataLokasi, dataPenerima, dataRetensi, dataLampiran, handleReloadPenerima, onSave, onSaveDispo, onChangeKontak, onNativeChange, handleClose, handleRemovePenerima, onPenerima, handleCancel, handleReload, onModalShow, setIsStagingFileForMarginTop, handleReset, recordAgenda, onPilihRef, unitId, mode, ...props }: Props) => ( <Drawer name="FormAgMasukView" data-testid="drawer" className={classnames('FormAgMasukView')} visible={true} title={t('agmasuk.ADD_AGMASUK')} width={'80%'} okText="Simpan" cancelText="Batal" onClose={onClose} closable={true} footer={ <span className={'right'}> <DrafButton onClick={onSave} /> <DistribusiButton onClick={onSaveDispo} /> </span> } > {mode} <Row> <Form form={form} onFinish={onFinish} colon={false} data-testid="form" labelCol={{ span: 5, }} wrapperCol={{ span: 19, }} scrollToFirstError={true} initialValues={{ surat_registrasi: regId, dispo_penerima: [''], surat_agenda: recordAgenda, penerima_level: penerima_level, surat_retensi_tgl: retensi, surat_tgl: native, }} > <Row gutter={24}> <Col span={12} key={1}> <Card className={classnames('card-form')}> <Form data-testid="form-berkas" form={form} scrollToFirstError={true} initialValues={formInitialValues} > <UploadFiles data-testid="upload-files" setIsStagingFileForMarginTop={setIsStagingFileForMarginTop} suratId={suratArsip} handleReload={handleReload} /> </Form> </Card> <Card className={classnames('card-form')}> <h3>{t('agmasuk.ISI_SURAT')}</h3> <Form.Item label={t('agmasuk.NO_REG')} data-testid="input-surat-registrasi" name="surat_registrasi" rules={[{ required: false }]} labelAlign="left" > <p className={classnames('readonly')}>{regId}</p> <Divider className={classnames('label-readonly')}></Divider> <p className={classnames('notes')}>{t('agmasuk.NO_REG_DESC')}</p> </Form.Item> <Form.Item label={t('agmasuk.DARI')} data-testid="input-surat-pengirim" labelAlign="left"> <Input.Group compact> <Form.Item name="surat_pengirim" noStyle> <AutoComplete allowClear showSearch onInputKeyDown={onChangeKontak} placeholder={t('agmasuk.DARI_PLACEHOLDER')} > {dataKontak?.map((kontak) => { return ( <Option key={kontak.kontak_nama} value={kontak.surat_kontak?.kontak_nama} > {kontak.surat_kontak? kontak.surat_kontak.kontak_nama: kontak.kontak_nama} </Option> ); })} </AutoComplete> </Form.Item> </Input.Group> </Form.Item> <Form.Item label={t('agmasuk.PERIHAL')} name="surat_perihal" rules={[{ required: true }]} labelAlign="left" data-testid="input-surat-perihal" > <Input.TextArea placeholder={t('agmasuk.PERIHAL_PLACEHOLDER')} allowClear /> </Form.Item> <Form.Item label={t('agmasuk.KEPADA')} name="surat_tujuan" rules={[{ required: false }]} labelAlign="left" data-testid="input-surat-tujuan" > <Input.TextArea placeholder={t('agmasuk.KEPADA_PLACEHOLDER')} allowClear /> </Form.Item> <Form.Item label={<label></label>} name="surat_israhasia" rules={[{ required: false }]} labelAlign="left" data-testid="input-surat-israhasia" > <Checkbox> <span style={{ fontWeight: 'bold', marginBottom: '1em' }}> {t('agmasuk.ISRAHASIA')} </span> </Checkbox> <div style={{ width: '40vh' }}> <p className="light">{t('agmasuk.ISRAHASIA_DESC')}</p> </div> </Form.Item> <Form.Item label={t('agmasuk.NO_SURAT')} name="surat_nomor" rules={[{ required: false }]} labelAlign="left" data-testid="input-surat-nomor" > <Input placeholder={t('agmasuk.NO_SURAT_PLACEHOLDER')} allowClear /> </Form.Item> <Form.Item label={t('agmasuk.TGL_SURAT')} name="surat_tgl" rules={[{ required: true }]} labelAlign="left" data-testid="input-surat-tgl" > <Input value={native} inputProps={{ min: '2019-01-24', max: '2020-05-31' }} type="date" onChange={onNativeChange} placeholder={t('agmasuk.TGL_SURAT_PLACEHOLDER')} /> </Form.Item> <Form.Item label={t('agmasuk.LAMPIRAN')} labelAlign="left"> <Input.Group compact> <Form.Item name="surat_lampiran" data-testid="input-surat-lampiran" noStyle> <Input style={{ width: '55%' }} placeholder={t('agmasuk.LAMPIRAN_PLACEHOLDER')} /> </Form.Item> <Form.Item name="surat_lampiran_sub" data-testid="input-surat-lampiran-sub" noStyle> <Select placeholder={t('agmasuk.LAMPIRAN_TIPE_PLACEHOLDER')} style={{ width: '45%' }} > {dataLampiran?.map((lampiran) => { return ( <Option key={lampiran.lampiran_id} value={ lampiran.surat_lampiran_sub?.lampiran_nama } > {lampiran.surat_lampiran_sub? lampiran.surat_lampiran_sub.lampiran_nama: lampiran.lampiran_nama} </Option> ); })} </Select> </Form.Item> </Input.Group> </Form.Item> <Form.Item label={t('agmasuk.NO_AGENDA')} labelAlign="left"> <Input.Group compact> <Form.Item name="surat_agenda" noStyle data-testid=""> <div style={{ width: '50%' }} className={classnames('label-readonly-agenda')} > <p className={classnames('readonly')}>{recordAgenda}</p> </div> </Form.Item> <Form.Item name="surat_agenda_sub" noStyle> <Input addonBefore="Sub Nomer" maxLength={3} placeholder="...." style={{ width: '50%' }} /> </Form.Item> </Input.Group> <p className={classnames('notes')}>{t('agmasuk.NO_AGENDA_DESC')}</p> </Form.Item> <Form.Item label={t('agmasuk.JENIS')} labelAlign="left"> <Input.Group compact> <Form.Item name="surat_jenis" noStyle> <Select placeholder={t('agmasuk.JENIS_PLACEHOLDER')} allowClear > {dataJenis?.map((jenis) => { return ( <Option key={jenis.jenis_id} value={jenis.surat_jenis?.jenis_nama} > {jenis.surat_jenis? jenis.surat_jenis?.jenis_nama: jenis.jenis_nama} </Option> ); })} </Select> </Form.Item> </Input.Group> </Form.Item> <Form.Item label={t('agmasuk.KLASIFIKASI')} labelAlign="left"> <Input.Group compact> <Form.Item name="surat_kelas" noStyle> <Select placeholder={t('agmasuk.KLASIFIKASI_PLACEHOLDER')} allowClear > {dataKelas?.map((kelas) => { return ( <Option key={kelas.kelas_id} value={kelas.surat_kelas?.kelas_nama} > {kelas.surat_kelas? kelas.surat_kelas?.kelas_nama: kelas.kelas_nama} </Option> ); })} </Select> </Form.Item> </Input.Group> </Form.Item> <Form.Item label={t('agmasuk.PRIORITAS')} labelAlign="left"> <Input.Group compact> <Form.Item name="surat_prioritas" noStyle> <Select placeholder={t('agmasuk.PRIORITAS_PLACEHOLDER')} allowClear > {dataPrioritas?.map((prioritas) => { return ( <Option key={prioritas.prioritas_id} value={prioritas.prioritas_id} > {prioritas.surat_prioritas_tgl? prioritas.surat_prioritas_tgl.prioritas_nama: prioritas.prioritas_nama} </Option> ); })} </Select> </Form.Item> </Input.Group> </Form.Item> <Form.Item label={t('agmasuk.MEDIA')} labelAlign="left"> <Input.Group compact> <Form.Item name="surat_media" noStyle> <Select placeholder={t('agmasuk.MEDIA_PLACEHOLDER')} allowClear > {dataMedia?.map((media) => { return ( <Option key={media.media_id} value={media.surat_media?.media_nama} > {media.surat_media? media.surat_media.media_nama: media.media_nama} </Option> ); })} </Select> </Form.Item> </Input.Group> </Form.Item> <Form.Item label={t('agmasuk.LOKASI')} labelAlign="left"> <Input.Group compact> <Form.Item name="surat_lokasi" noStyle> <Select placeholder={t('agmasuk.LOKASI_PLACEHOLDER')} allowClear > {dataLokasi?.map((lokasi) => { return ( <Option key={lokasi.lokasi_id} value={lokasi.surat_lokasi?.lokasi_nama} > {lokasi.surat_lokasi? lokasi.surat_lokasi.lokasi_nama: lokasi.lokasi_nama} </Option> ); })} </Select> </Form.Item> </Input.Group> </Form.Item> <Form.Item label={t('agmasuk.CATATAN')} name="surat_catatan" rules={[{ required: false }]} labelAlign="left" > <Input.TextArea placeholder={t('agmasuk.CATATAN_PLACEHOLDER')} allowClear /> </Form.Item> <Form.Item label="" name="surat_registrasi" rules={[{ required: false }]} labelAlign="left" > <Input placeholder="No registrasi otomatis terisi" hidden={true} value={regId} /> </Form.Item> <Form.Item label="" name="surat_agenda" rules={[{ required: false }]} labelAlign="left" > <Input hidden={true} value={recordAgenda} /> </Form.Item> <Form.Item name="surat_suratref" style={{ display: 'nonen' }}> <Input value={syncedAdmin} hidden={true} /> </Form.Item> </Card> </Col> <Col span={12} key={2}> <AddReferensi name="agkeluar" syncedNo={syncedNo} syncedReferensi={syncedReferensi} doModalShow={onModalShow} visibleRefForm={visibleRefForm} rowSelection={rowSelection} onReset={handleReset} onPilihRef={onPilihRef} onClose={handleClose} unitId={unitId} /> <h3>{t('agmasuk.RETENSI')}</h3> <Form.Item labelCol={{ span: 14 }} wrapperCol={{ span: 10 }} label={t('agmasuk.RETENSI_DESC')} name="surat_retensi" rules={[ { required: false, }, ]} labelAlign="left" > <Select style={{ width: '100%' }} placeholder={t('agmasuk.RETENSI_PLACEHOLDER')} allowClear > {dataRetensi?.map((retensi) => { return ( <Option key={retensi.retensi_id} value={retensi.retensi_id}> {retensi.retensi_nama} </Option> ); })} </Select> </Form.Item> <AddPenerima dataPenerima={dataPenerima} onPenerima={onPenerima} handleRemovePenerima={handleRemovePenerima} form={form} /> </Col> </Row> </Form> </Row> </Drawer> ); export default pipe(withTranslation(), memo)(FormAgMasukView);

FormAgMasuk.View.Test.js <--- The test

 import 'init/matchMedia.mock'; import { cleanup, fireEvent, render, screen } from '@testing-library/react'; import FormAgMasukView from './FormAgMasukView'; import { configureStore } from '@reduxjs/toolkit'; import { createStore } from 'components/Permissible'; import { initialState, reducer } from './FormAgMasuk'; import { Provider } from 'react-redux'; import store from 'init/Store'; afterEach(() => cleanup()); beforeEach(() => { jest.spyOn(console, 'warn').mockImplementation(() => {}); }); describe('test render FormAgMasuk with default props', () => { it('should render with drawer', () => { render( <Provider store={store}> <FormAgMasukView /> </Provider> ); const drawer = screen.getByTestId('drawer'); expect(drawer).toBeTruthy(); }); it('should render form', () => { render( <Provider store={store}> <FormAgMasukView /> </Provider> ); const form = screen.getByTestId('form'); expect(form).toBeTruthy(); }); it('should render upload file section', () => { render( <Provider store={store}> <FormAgMasukView /> </Provider> ); const formBerkas = screen.getByTestId('form-berkas'); expect(formBerkas).toBeTruthy(); }); it('should render input surat registrasi', () => { render( <Provider store={store}> <FormAgMasukView /> </Provider> ); const inputSuratRegistrasi = screen.getByTestId('input-surat-registrasi'); expect(inputSuratRegistrasi).toBeTruthy(); }); it('should render input pengirim surat', () => { render( <Provider store={store}> <FormAgMasukView /> </Provider> ); const inputSuratPengirim = screen.getByTestId('input-surat-pengirim'); expect(inputSuratPengirim).toBeTruthy(); }); it('should render input perihal surat', () => { render( <Provider store={store}> <FormAgMasukView /> </Provider> ); const inputSuratPerihal = screen.getByTestId('input-surat-perihal'); expect(inputSuratPerihal).toBeTruthy(); }); it('should render input tujuan surat', () => { render( <Provider store={store}> <FormAgMasukView /> </Provider> ); const inputSuratTujuan = screen.getByTestId('input-surat-tujuan'); expect(inputSuratTujuan).toBeTruthy(); }); it('should render input rahasia surat', () => { render( <Provider store={store}> <FormAgMasukView /> </Provider> ); const inputSuratRahasia = screen.getByTestId('input-surat-israhasia'); expect(inputSuratRahasia).toBeTruthy(); }); it('should render input nomor surat', () => { render( <Provider store={store}> <FormAgMasukView /> </Provider> ); const inputSuratNomor = screen.getByTestId('input-surat-nomor'); expect(inputSuratNomor).toBeTruthy(); }); it('should render input tanggal surat', () => { render( <Provider store={store}> <FormAgMasukView /> </Provider> ); const inputSuratTanggal = screen.getByTestId('input-surat-tgl'); expect(inputSuratTanggal).toBeTruthy(); }); });

note

  • sorry for my bad English
  • any help will be appreciated like books, article, tutorial videos, etc.

Since antd has it's own specs, I tend to mock their components to something that I can test myself.

jest.mock('antd', () => {
  return {
    ...jest.requireActual('antd'),
    Drawer: jest.fn(p => p.children), // I don't care what drawer does, I just want it's children to render
    Row: jest.fn(p => p.children),
    Col: jest.fn(p => <div data-testid="myCol">{p.children}</div>), // maybe wrap Col inside a div?
    Autocomplete: jest.fn(() => 'Autocomplete'), // here I don't even need to render anything, just as string
  }
});

I even mock Form's to just return an html form to just test onSubmit

...
Form: jest.fn(p => <form onSubmit={p.onFinish}>{p.children}</form>),
...

I hope this helps, basically my concept is to mock antd components to something that I can interact with myself without tampering with their logic.

using jest@26.6.0

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM