What does #describe and #it methods do in TDD react testing? - javascript

I'm learning TDD with React from this site, but don't understand how the author got describe and it, aren't these usually from Jasmine? I don't see this package in the author's node_modules at his github nor does his tests.js import anything that looks like describe or it. Where are these two methods coming from?
import React from 'react';
import { expect } from 'chai';
import { shallow, mount, render } from 'enzyme';
describe('Test suite for User component', () => {
it('UserComponent should exist', () => {
let wrapper = shallow(<User />)
expect(wrapper).to.exist;
});
});

If that is the only it() statement that you are going to be using in your test suite, you do not really need the describe() block.
The describe() construct does indeed exist in Jest, it exists in Mocha as well.
The describe() function is used to group together certain sets of tests that have some common setup and tear down for each of them. This is why I said, based on the code you pasted, if you have nothing further to test, you do not need that describe() function.
So when you run create-react-app one of the libraries that got loaded automatically was the Jest test suite.
I would also rewrite that test, instead of UserComponent should exist, I would do
it('shows a user component', () => {
let wrapper = shallow(<User />);
expect(wrapper.find(User).length).toEqual(1);
});
So this is where I recommend to not just follow tutorials, but look up the documentation of the tools they are having you utilize in these tutorials. In the case of Enzyme, there is a really nice method called find() to find the component and it offers an array so you can add on .length and since its just one component of User you can add at the end .toEqual(1);

Related

How to test different types of test for a single render in React with testing-library?

I'm new in TDD for the React. I've decided to use the react-testing-library to start TDD for development. Suppose that, I should check a prop and simple text in component:
import { render, screen } from '#testing-library/react';
import Card from '../Card';
test('render without crash', () => {
render(<Card />);
expect(screen.getByText('Card Component')).toBeInTheDocument();
});
test('title', () => {
render(<Card title="test" />);
expect(screen.getByText('test')).toBeInTheDocument();
});
I used render two times two check different types of rendering for my component. But I was worry about performance... Is it best practice to separately use render in any tests? or I should create something like this common variable:
const Component = render(<Card title={...} prop2={} prop3={} ... />);
then use Component instead using render again?
I don't think this would be a bad practice. I usually use one of these approaches :
render my component once in a beforeEach, and use it in multiple test(), if I always need the same setup for each test (props, contexts, redux store...),
render my component in each test(), so I can adjust props and context and test multiple configurations.
See https://stackoverflow.com/a/61838982/2295549 for a more complete explanation, and some pros/cons.
But using render multiple times is not a bad practice, in fact it is a pattern used in official docs.

Javascript pure function import strategy

I have a class file, utility.js for all the common functions.
However some of the functions require certain library import
e.g: NetInfo library
utility.js
import NetInfo from "#react-native-community/netinfo";
export async function networkConnection() {
const state = await NetInfo.fetch();
return state.type;
}
However, in order for utility.js to be reusable in another project, another project has to have NetInfo installed. Is it a good practice if instead of importing modules directly, I import only when I need to use it, and pass the import object along to the function?
utility.js
export async function networkConnection({ NetInfo }) {
const state = await NetInfo.fetch();
return state.type;
}
and when using it
app.js
import NetInfo from "#react-native-community/netinfo";
import { networkConnection } from "./utility.js"
const network = networkConnection({ NetInfo })
This way, I can copy and paste utility.js to any project, without the need to install all the import packages. Also, this pattern seems to be able to resolve common Circular Dependencies error by limiting the import statement.
Is this the best practice for creating a common, reusable function file?
Your question illustrates the difference between a closure and a plain function, however, neither are pure.
If the function only serves to await a promise and return a property value, it doesn't really make sense to use the non-closure approach... unless you've created a module (utility.js in your example) with other exports unrelated to the NetInfo context. If that's the case, I think that's the issue to focus on: reorganization of your code's concerns.
How many characters it takes to get the value two ways:
console.log(`await networkConnection()`.length); // 25
console.log(`(await NetInfo.fetch()).type`.length); // 28
Is it worth the abstraction? Up to your brain and your fingers.

Jest mocking module implementation with .mockImplemetation

Can anyone help here. I am really frustrated with how the mockImplementation works.
So, first of all I am using jest for node testing. I am using the commonjs modules. what I wanna do is that I am trying to mock a module using mockImplementation() and change its implementation between different tests according to this documentation here: https://jestjs.io/docs/en/es6-class-mocks#replacing-the-mock-using-mockimplementation-docs-en-mock-function-api-mockfnmockimplementationfn-or-mockimplementationonce-docs-en-mock-function-api-mockfnmockimplementationoncefn.
My code look like this:
const exportBigQueryTableModule =require('../repository/exportBigQueryTable')
jest.mock('../repository/exportBigQueryTable')
describe('deleting files on table export fail', () => {
mockExportBigQueryTable = jest
.fn(() => Promise.resolve())
.mockResolvedValueOnce()
.mockRejectedValueOnce(new Error('Could not export table'))
exportBigQueryTableModule.mockImplementation(mockExportBigQueryTable)
it(' should do some test', () => {})
})
The problem here is that looks like that this line jest.mock('../repository/exportBigQueryTable') create for me a default mock kind of jest.fn() and the module is always loaded with that default function. So the mock function that I did provide on the test using the mockImplementation never overrides the previous one, I do not get what is the problem here. Why the same exmaple on the official documentation works the only difference is that it uses es6 modules on the doc sample.
I am not sure if I am missing something here.

Using Cucumber.js with Jest

I am using Jest for my unit tests and I'm in the process of integrating Cucumber.js for running specs written in Gherkin.
I have it all set up and it's working, but I am running into one problem: How can I use Jest's expect? I could use chai's, but I'd like to keep the expect syntax the same between my unit tests and my step definitions (I don't want to.equal in my step definitions and toEqual in my unit tests).
How can I do that? After some digging it seems as if Jest relies on the expect npm package. I could depend on that package explicitly in my package.json, but I'd much rather use my existing Jest dependency. Maybe that's not possible, but I hope it is.
Another option would be to somehow execute the Gherkin specs with the Jest test-runner. I'd be open to that option as well. At the moment I'm running them by calling cucumber.js separately from my Jest test-runner.
My react-native environment:
"cucumber": "^4.1.0",
"jest": "22.4.2",
In my steps definition file, I just require it like this
const { Given, Then, When } = require('cucumber');
const expect = require('expect');
Expect is part of Jest, so you can import it as its own object. Then I can use it wherever I need an assertion. Note: newMember is declared and populated elsewhere.
Given('Sara has provided account details', function() {
for (const prop in newMember) {
expect(newMember[prop]).toBeTruthy();
}
});
Hope that helps.
expect is a globally scoped during jest runtime. So as long as you are running jest it will be available. I'm using this package (needs some config to transform correctly to your babel config): gherkin-jest
Here's a feature using the DOM-testing example from the jest docs:
Feature: Using feature files in jest and cucumber
As a developer
I want to write tests in cucumber and jest
So that businesspeople understand tests and I can test React
Scenario: Emoji toggles upon checking and unchecking the checkbox
Given I did not check the checkbox, so the label is "😭"
When I check the box and the emoji toggles to be "😎"
import {cucumber as c} from 'gherkin-jest'
import React from 'react'
import {mount} from 'enzyme'
import {Checkbox} from '../src/components'
c.defineCreateWorld(() => ({
checkbox:null
}))
c.defineRule('I did not check the checkbox so the label is {string}', (world, off) => {
world.checkbox = mount(<Checkbox labelOff={off} />)
expect(world.checkbox.text()).toBe(off)
})
c.defineRule('I checked the box and the emoji toggles to be {string}', (world, on) =>{
world.checkbox = mount(<Checkbox labelOn={on}/>)
world.checkbox.find('TouchableOpacity').props().onPress()
expect(world.checkbox.text()).toBe(on)
})
This issue I posted gives an example of the config.
An alternative would be to use jest-cucumber
https://www.npmjs.com/package/jest-cucumber.
gives you the flexibility of using both frameworks

Import `spyOn` function to get rid of 'not defined' eslint error

I have a unit test that uses spyOn method from jest.
import React from 'react';
import expect from 'jest-matchers';
import PointsAwardingPage from '../PointsAwardingPage';
import PointsAwardingForm from '../children/PointsAwardingForm';
import { shallow } from 'enzyme';
it("should call change method in form", () => {
// given
spyOn(PointsAwardingPage.prototype, 'change').and.callThrough();
const form = shallow(<PointsAwardingPage />).find('PointsAwardingForm');
// when
form.props().onChange();
// then
expect(PointsAwardingPage.prototype.change).toHaveBeenCalled();
});
Everything works well. However, I see the following eslint error message regarding the spyOn function call.
spyOn is not defined (no-undef).
Which import statement can I use in order to get rid of this error?
Although a global comment is a valid solution, I believe you could simply use jest.spyOn() instead.
Don't forget to define jest in your .eslintrc:
"env": {
"jest": true
}
That's because spyOn is provided by the test environment - in your case Jest - thus it's not defined by you.
ESLint looks for definitions in your code only.
An easy and safe way to get rid of it is to place a comment /*global spyOn*/ at the top of your test file, which tells ESLint that you have defined it, without actually doing so.

Categories