Test Driven Development
Frontend
Possible or impossible?
Who Am I?
- Full Stack Developer at Lean Mind
- Passionate about development
- Typescript lover ❤️
Adrián Ferrera González
@afergon
adrian-afergon
Lean Coders
This is a grandparent history
- The good
- The bad
- The mistakes
What is TDD?
Classic way:
TDD way:
Why we use it?
FF -> Fast feedback
Hight code coverage
Ensure the features
Other way to document
I can do it on my way!!
- I'm faster without TDD
- Is imposible to test the unexistent
- My client don't want it!!!
- What time expend in find a bug?
- Are you testing code or features?
- Do you tell your surgeon how to do it?
Is necessary?
- expect(true).toBeTruthy()
- You don't trust in your libs
Propably you have lisened something like...
This is not about TDD,
is about the way you test
What is the purpouse?
This is not about create test
Is about develop based in use small use cases
Using the test as tools
Tests Types
- e2e
- Unitary
- Integration
That I ussually use
Tests Types
- e2e
- Unitary
- Integration
That I ussually use
Expects are use cases
Clone of real environment
Are to expensive
Real coverage
Tests Types
- e2e
- Unitary
- Integration
That I ussually use
Expects are abstraction functionalities
No require specific configs
Are faster and cheaper
Local component coverage
Tests Types
- e2e
- Unitary
- Integration
That I ussually use
Expects are abstraction functionalities
Require mocks to set limits
Perfect balance
Important coverage but not always real
Tests Types
- e2e
- Unitary
- Integration
That I ussually use
IMPORTANT!!!
You need an architecture!!
References for Architecture
Books:
Videos:
Slides:
Before start
let's talk about concepts
The Approach
OUTSIDE-IN
INSIDE-OUT
Emerging architecture
Componentisation
Predefined architecture
Fuzzy components
Testign Concepts
Before test
Mock
Spy
Replace a real function or var, by other that we want
Lisent a value for make questions
With Jest:
const foo = jest.fn();
const message = 'Hello TLP Innova';
foo(message);
expect(foo).toHaveBeenCalled();
expect(foo).toHaveBeenCalledWith(message);
const spy = jest.spyOn(video, 'play', 'get'); // we pass 'get'
const isPlaying = video.play;
expect(spy).toHaveBeenCalled();
expect(isPlaying).toBe(true);
spy.mockRestore();
Mock a function or mock an object
Concepts
Before test
Black-box
SCHRÖDINGER CAT
Concepts
About React
React
Redux
Hooks
Library to create components
Pattern to handle the state
Functions to share logic
We have to mount it
We have to use as black-box
We have to test independently
Providers
React Tool to handle the context
REAL CASE
Define use cases
- We want to pick a champion and see his stats and general info.
In main page
- We display all available champions, when we pick one, he/she is added to the build, then we recieve a list of suggestions champs that match well with our team.
In team builder
In best builds
- We want to display best ranked builds
Define use cases
Define use cases
This tests take a lot of time to be runned
So it is very important to be very specific
Conclusions
Emerged Design
How can we do it
Hight Order Components
TIP: The end goal is not to break the app
TIP: Don't rush through the code
# Help TIP 1:
describe('Champion items', () => {
it('should be displayed', () => {
expect(wrapper.exists()).toBeTruthy();
});
});
describe('Champion items', () => {
it('should be displayed', () => {
expect(wrapper.exists()).toBeTruthy(); // what is wrapper?
});
});
describe('Champion items', () => {
it('should be displayed', () => {
const wrapper = shallow(
<ChampionItems
service={aService}
isLoading={aLoadState}
/>
);
expect(wrapper.exists()).toBeTruthy();
});
});
describe('Champion items', () => {
it('should be displayed', () => {
const wrapper = shallow(
<ChampionItems
service={aService}
isLoading={aLoadState}
/>
); // and this props? :(
expect(wrapper.exists()).toBeTruthy();
});
});
describe('Champion items', () => {
it('should be displayed', () => {
const aLoadState = false;
const aService = { getItems: () => Promise.resolve(someItems)}
const wrapper = shallow(
<ChampionItems
service={aService}
isLoading={aLoadState}
/>
);
expect(wrapper.exists()).toBeTruthy();
});
});
describe('Champion items', () => {
it('should be displayed', () => {
const someItems = ['B.F. Sword', 'Recurve Bow', 'Spatula'];
const aLoadState = false;
const aService = { getItems: () => Promise.resolve(someItems)}
const wrapper = shallow(
<ChampionItems
service={aService}
isLoading={aLoadState}
/>
);
expect(wrapper.exists()).toBeTruthy();
});
});
Go from expect to definition
TODO: introduce jest
Emerged Design
Custom tool to generate boilerplate
# Help TIP 2:
Remeber true === true?
Emerged Design
import { shallow } from 'enzyme';
import * as React from 'react';
import { Image} from './';
describe('Image', ()=> {
it('should display the component', ()=>{
const wrapper = shallow(<Image />);
expect(wrapper.exists()).toBeTruthy();
});
});
import { shallow } from 'enzyme';
import * as React from 'react';
import { Image} from './';
describe('Image', ()=> {
it('should display the component', ()=>{
const wrapper = shallow(<Image />);
expect(wrapper.exists()).toBeTruthy();
});
it('should display the image source', function () {
const wrapper = shallow(<Image src="irrelevant source"/>);
expect(wrapper.exists()).toBeTruthy();
});
});
import { shallow } from 'enzyme';
import * as React from 'react';
import { Image} from './';
describe('Image', ()=> {
it('should display the image source', function () {
const wrapper = shallow(<Image src="irrelevant source"/>);
expect(wrapper.exists()).toBeTruthy();
});
});
Refactor
import * as React from 'react';
import './Image.scss';
type ImageProps = React.DetailedHTMLProps<
React.ImgHTMLAttributes<HTMLImageElement>,
HTMLImageElement
>;
export const Image: React.FC<ImageProps> = (props) => (
<img {...props} />
);
Image.displayName = 'Image';
Implement
import { shallow } from 'enzyme';
import * as React from 'react';
import { Image} from './';
describe('Image', ()=> {
it('should display the component', ()=>{
const wrapper = shallow(<Image />);
expect(wrapper.exists()).toBeTruthy();
});
it('should display the image source', function () {
const wrapper = shallow(<Image src="irrelevant source"/>);
expect(wrapper.exists()).toBeTruthy();
});
});
Emerged Design
import * as React from 'react';
import './ChampionImage.scss';
import { Image } from '../Image/';
type ChampionImageProps = {
id:string,
name: string,
src: string,
onClick: (id: string) => void
};
export const ChampionImage: React.FC<ChampionImageProps> =
({id, name, src, onClick}) => {
const handleClick = () => {
onClick(id)
};
return (
<div onClick={handleClick}>
<Image src={src} alt={name} data-test-id="image"/>
</div>
)};
ChampionImage.displayName = 'ChampionImage';
it('should find the image inside', () => {
});
it('should call an event when is clicked', () => {
});
it('should find the image inside', () => {
const wrapper = shallow(
<ChampionImage
src="irrelevant champion image"
name="Irrelevant champion name"
/>);
expect(
wrapper.find('[data-test-id="image"]').exists()
).toBeTruthy();
});
it('should call an event when is clicked', () => {
});
it('should find the image inside', () => {
const wrapper = shallow(
<ChampionImage
src="irrelevant champion image"
name="Irrelevant champion name"
/>);
expect(
wrapper.find('[data-test-id="image"]').exists()
).toBeTruthy();
});
it('should call an event when is clicked', () => {
});
import * as React from 'react';
import './ChampionImage.scss';
import { Image } from '../Image/';
type ChampionImageProps = {
name: string,
src: string,
};
export const ChampionImage: React.FC<ChampionImageProps> =
({name, src}) => {
return (
<div>
<Image src={src} alt={name} data-test-id="image"/>
</div>
)};
ChampionImage.displayName = 'ChampionImage';
it('should find the image inside', () => {
const wrapper = shallow(
<ChampionImage
src="irrelevant champion image"
name="Irrelevant champion name"
/>);
expect(
wrapper.find('[data-test-id="image"]').exists()
).toBeTruthy();
});
it('should call an event when is clicked', () => {
const aClickHandler = jest.fn();
const wrapper = shallow(
<ChampionImage
id="irrelevant id"
src="irrelevant champion image"
name="Irrelevant champion name"
onClick={aClickHandler}
/>);
wrapper.simulate('click');
expect(aClickHandler).toHaveBeenCalledWith("irrelevant id");
});
import * as React from 'react';
import './ChampionImage.scss';
import { Image } from '../Image/';
type ChampionImageProps = {
id?:string,
name: string,
src: string,
onClick?: (id: string) => void
};
export const ChampionImage: React.FC<ChampionImageProps> =
({id, name, src, onClick}) => {
const handleClick = () => {
if(onClick && id) {
onClick(id)
}
};
return (
<div onClick={handleClick}>
<Image src={src} alt={name} data-test-id="image"/>
</div>
)};
ChampionImage.displayName = 'ChampionImage';
it('should find the image inside', () => {
const wrapper = shallow(
<ChampionImage
src="irrelevant champion image"
name="Irrelevant champion name"
/>);
expect(
wrapper.find('[data-test-id="image"]').exists()
).toBeTruthy();
});
it('should call an event when is clicked', () => {
const aClickHandler = jest.fn();
const wrapper = shallow(
<ChampionImage
id="irrelevant id"
src="irrelevant champion image"
name="Irrelevant champion name"
onClick={aClickHandler}
/>);
wrapper.simulate('click');
expect(aClickHandler).toHaveBeenCalledWith("irrelevant id");
});
Implement
x2
Emerged Design
Take care with compilation errors
# Help TIP 3:
Emerged Design
When we pass the test, we can refactor this code
type ChampionId = string;
interface Champion {
id: ChampionId,
name: string,
image: string
}
let aChampion: Champion;
beforeEach(() => {
aChampion = {
id: "Irrelevant champion id",
name: "Irrelevant champion name",
image: "Irrelevant champion image"
}
});
type ChampionImageProps = {
id?:string,
name: string,
src: string,
onClick?: (id: string) => void
champion?: Champion;
}
<div onClick={handleClick}>
<Image src={src} alt={name} data-test-id="image"/>
</div>
<div onClick={handleClick}>
<Image src={champion.image} alt={champion.name} data-test-id="image"/>
</div>
it('should find the image inside', () => {
const wrapper = shallow(
<ChampionImage
src="irrelevant champion image"
name="Irrelevant champion name"
/>);
expect(
wrapper.find('[data-test-id="image"]').exists()
).toBeTruthy();
});
it('should call an event when is clicked', () => {
const aClickHandler = jest.fn();
const wrapper = shallow(
<ChampionImage
id="irrelevant id"
src="irrelevant champion image"
name="Irrelevant champion name"
onClick={aClickHandler}
/>);
wrapper.simulate('click');
expect(aClickHandler).toHaveBeenCalledWith("irrelevant id");
});
it('should find the image inside', () => {
const wrapper = shallow(
<ChampionImage
src="irrelevant champion image"
name="Irrelevant champion name"
champion={aChampion}
/>);
expect(
wrapper.find('[data-test-id="image"]').exists()
).toBeTruthy();
});
it('should call an event when is clicked', () => {
const aClickHandler = jest.fn();
const wrapper = shallow(
<ChampionImage
id="irrelevant id"
src="irrelevant champion image"
name="Irrelevant champion name"
champion={aChampion}
onClick={aClickHandler}
/>);
wrapper.simulate('click');
expect(aClickHandler).toHaveBeenCalledWith("irrelevant id");
});
it('should find the image inside', () => {
const wrapper = shallow(
<ChampionImage
champion={aChampion}
/>);
expect(
wrapper.find('[data-test-id="image"]').exists()
).toBeTruthy();
});
it('should call an event when is clicked', () => {
const aClickHandler = jest.fn();
const wrapper = shallow(
<ChampionImage
champion={aChampion}
onClick={aClickHandler}
/>);
wrapper.simulate('click');
expect(aClickHandler).toHaveBeenCalledWith("irrelevant id");
});
Paralel change!!
Emerged Design
Now let's create a Champion selector
import { shallow } from 'enzyme';
import * as React from 'react';
import { ChampionSelector} from './';
describe('ChampionSelector', ()=> {
it('should display the component', ()=>{
const wrapper = shallow(<ChampionSelector />);
expect(wrapper.exists()).toBeTruthy();
})
});
champions
import { shallow } from 'enzyme';
import * as React from 'react';
import { ChampionSelector} from './';
import {Champion} from "../ChampionImage/ChampionImage.spec";
describe('ChampionSelector', ()=> {
it('should display the champions', ()=>{
const someChampions: Champion[] = [];
const wrapper = shallow(<ChampionSelector champions={someChampions}/>);
const championImages = wrapper.find('ChampionImage');
expect(championImages.length).toBe(someChampions.length);
})
});
import { shallow } from 'enzyme';
import * as React from 'react';
import { ChampionSelector} from './';
import {Champion} from "../ChampionImage/ChampionImage.spec";
describe('ChampionSelector', ()=> {
it('should display the champions', ()=>{
const someChampions: Champion[] = [aatrox, kayle, fiora];
const wrapper = shallow(<ChampionSelector champions={someChampions}/>);
const championImages = wrapper.find('ChampionImage');
expect(championImages.length).toBe(someChampions.length);
})
});
Emerged Design
Building helpers
import { shallow } from 'enzyme';
import * as React from 'react';
import { ChampionSelector} from './';
import {Champion} from "../ChampionImage/ChampionImage.spec";
describe('ChampionSelector', ()=> {
it('should display the champions', ()=>{
const someChampions: Champion[] = [aatrox, kayle, fiora];
const wrapper = shallow(<ChampionSelector champions={someChampions}/>);
const championImages = wrapper.find('ChampionImage');
expect(championImages.length).toBe(someChampions.length);
})
});
const aatrox: Champion = {};
const kayle: Champion = {};
const fiora: Champion = {};
const someChampions: Champion[] = [aatrox, kayle, fiora];
const buildChampion = ({id, name, image}: Champion):Champion => ({
id: id ? id : 'irrelevant id',
name: name ? name : 'irrelevant name',
image: image ? image : 'irrelevant image'
});
it('should display the champions', ()=>{
const aatrox: Champion = buildChampion({name: 'Aatrox'} as Champion);
const kayle: Champion = buildChampion({name: 'Kayle'} as Champion);
const fiora: Champion = buildChampion({name: 'Fiora'} as Champion);
const someChampions: Champion[] = [atrox, kayle, fiora];
const wrapper = shallow(<ChampionSelector champions={someChampions}/>);
const championImages = wrapper.find('ChampionImage');
expect(championImages.length).toBe(someChampions.length);
});
# Help TIP 4:
Emerged Design
Now we should implement for green
import * as React from 'react';
import './ChampionSelector.scss';
import {Champion} from "../ChampionImage/ChampionImage.spec";
import {ChampionImage} from "../ChampionImage";
interface ChampionSelectorProps {
champions: Champion[];
}
export const ChampionSelector: React.FC<ChampionSelectorProps>
= ({champions}) =>
champions.map((champion) =>
<ChampionImage
key={champion.id}
champion={champion}
/>
);
ChampionSelector.displayName = 'ChampionSelector';
it('should display the champions', ()=>{
const aatrox: Champion = buildChampion({name: 'Aatrox'} as Champion);
const kayle: Champion = buildChampion({name: 'Kayle'} as Champion);
const fiora: Champion = buildChampion({name: 'Fiora'} as Champion);
const someChampions: Champion[] = [atrox, kayle, fiora];
const wrapper = shallow(<ChampionSelector champions={someChampions}/>);
const championImages = wrapper.find('ChampionImage');
expect(championImages.length).toBe(someChampions.length);
});
Implement
it('should select a champion when is clicked', () => {
const aSelectHandler = jest.fn();
const aatrox: Champion = buildChampion({name: 'Aatrox'} as Champion);
const kayle: Champion = buildChampion({name: 'Kayle'} as Champion);
const fiora: Champion = buildChampion({name: 'Fiora'} as Champion);
const someChampions: Champion[] = [aatrox, kayle, fiora];
const wrapper = shallow(
<ChampionSelector
champions={someChampions}
onSelect={aSelectHandler}
/>);
const aatroxImage = wrapper.find('[data-test-id]="Aatrox"');
aatroxImage.simulate('click');
expect(aSelectHandler).toHaveBeenCalled();
});
it('should select a champion when is clicked', () => {
const aSelectHandler = jest.fn();
const aatrox: Champion = buildChampion({name: 'Aatrox'} as Champion);
const kayle: Champion = buildChampion({name: 'Kayle'} as Champion);
const fiora: Champion = buildChampion({name: 'Fiora'} as Champion);
const someChampions: Champion[] = [aatrox, kayle, fiora];
const wrapper = shallow(
<ChampionSelector
champions={someChampions}
onSelect={aSelectHandler}
/>);
const aatroxImage = wrapper.find('[data-test-id]="Aatrox"');
aatroxImage.simulate('click');
expect(aSelectHandler).toHaveBeenCalled();
});
Implement
import * as React from 'react';
import './ChampionSelector.scss';
import {Champion} from "../ChampionImage/ChampionImage.spec";
import {ChampionImage} from "../ChampionImage";
interface ChampionSelectorProps {
champions: Champion[];
}
export const ChampionSelector: React.FC<ChampionSelectorProps>
= ({champions}) =>
champions.map((champion) =>
<ChampionImage
key={champion.id}
champion={champion}
onClick={onSelect}
data-test-id={champion.name}/>
);
ChampionSelector.displayName = 'ChampionSelector';
Emerged Design
describe('ChampionSelector', () => {
const aatrox: Champion = buildChampion({name: 'Aatrox'} as Champion);
const kayle: Champion = buildChampion({name: 'Kayle'} as Champion);
const fiora: Champion = buildChampion({name: 'Fiora'} as Champion);
const someChampions: Champion[] = [aatrox, kayle, fiora];
let wrapper: ShallowWrapper;
let aSelectHandler: jest.Mock;
beforeEach(() => {
aSelectHandler = jest.fn();
wrapper = shallow(<ChampionSelector champions={someChampions} onSelect={aSelectHandler}/>);
});
it('should display the champions', () => {
const championImages = wrapper.find('ChampionImage');
expect(championImages.length).toBe(someChampions.length);
});
it('should select a champion when is clicked', () => {
const aatroxImage = wrapper.find('[data-test-id="Aatrox"]');
aatroxImage.simulate('click');
expect(aSelectHandler).toHaveBeenCalled();
});
});
const buildChampion = ({id, name, image}: Champion): Champion => ({
id: id ? id : 'irrelevant id',
name: name ? name : 'irrelevant name',
image: image ? image : 'irrelevant image',
});
Define constants
Emerged Design
Champion Selector:
Image
Champion Image
Champion Selector
Emerged Design
Conclusions
- All time functional code
- We never have over ingeniering
Black box
The containers are a good element to test as a black box
Black box
Let's create a containter and check what it has to do
import { mount } from 'enzyme';
import * as React from 'react';
import { ChampionsInfo } from './';
describe('ChampionsInfo', () => {
let championService: ChampionService;
beforeEach(() => {
championService = new ChampionService();
});
it('should load a champions list when ' +
'the component is displayed', () => {
championService.getChampions = jest.fn(() =>
Promise.resolve(someChampions)
);
const wrapper = mount(
<ChampionsInfo
championService={championService}
/>);
wrapper.update();
expect(championService.getChampions).toHaveBeenCalled();
});
});
import * as React from 'react';
import './ChampionsInfo.scss';
import {useEffect, useState} from 'react';
export const ChampionsInfo: React.FC<{
championService: ChampionService
}> = ({championService}) => {
const [champions, setChampions] = useState([]);
useEffect(() => {
championService
.getChampions()
.then(setChampions);
}, []);
return (
<div className="ChampionsInfo">
Hello from ChampionsInfo!
</div>
);
};
ChampionsInfo.displayName = 'ChampionsInfo';
Implement
Black box
Evolution Problem
React Hooks
React
evolves
Enzyme
React-testing-library
We make a mistake no wrapping our libs
Black box
export interface ChampionService {
getChampions: () => Promise<Champion[]>;
}
describe('ChampionsInfo', () => {
const aatrox: Champion = { info: '', image: '', id: 'irrelevant 1', name: 'aatrox' };
const kayle: Champion = { info: '', image: '', id: 'irrelevant 2', name: 'kayle' };
const fiora: Champion = { info: '', image: '', id: 'irrelevant 3', name: 'fiora' };
const someChampions: Champion[] = [aatrox, kayle, fiora];
let championService: ChampionService;
beforeEach(() => {
championService = {
getChampions: jest.fn(async () => someChampions),
};
});
it('should load a champions list when the component is displayed', async () => {
const { container } = await render(
<ChampionsInfo championService={championService} />,
);
const championSelector = container.children[0];
const section = championSelector.children[0];
const displayedChampions = section.children;
expect(championService.getChampions).toHaveBeenCalled();
expect(displayedChampions.length).toEqual(someChampions.length);
});
});
interface ChampionsInfoProps {
championService: ChampionService;
}
export const ChampionsInfo: React.FC<ChampionsInfoProps> =
({ championService }) => {
const [champions, setChampions] = useState([] as Champion[]);
useEffect(() => {
championService.getChampions().then(setChampions);
}, [championService]);
return (
<div className="ChampionsInfo">
<ChampionSelector champions={champions} onSelect={() => ''} />
</div>
);
};
ChampionsInfo.displayName = 'ChampionsInfo';
Implement
export interface ChampionService {
getChampions: () => Promise<Champion[]>;
}
describe('ChampionsInfo', () => {
const aatrox: Champion = { info: '', image: '', id: 'irrelevant 1', name: 'aatrox' };
const kayle: Champion = { info: '', image: '', id: 'irrelevant 2', name: 'kayle' };
const fiora: Champion = { info: '', image: '', id: 'irrelevant 3', name: 'fiora' };
const someChampions: Champion[] = [aatrox, kayle, fiora];
let championService: ChampionService;
beforeEach(() => {
championService = {
getChampions: jest.fn(async () => someChampions),
};
});
it('should load a champions list when the component is displayed', async () => {
const { container } = await render(
<ChampionsInfo championService={championService} />,
);
const championSelector = container.children[0];
const section = championSelector.children[0];
const displayedChampions = section.children;
expect(championService.getChampions).toHaveBeenCalled();
expect(displayedChampions.length).toEqual(someChampions.length);
});
});
Black box
it('should load a champions list when the component is displayed', async () => { ... });
it('should select a champion and display the info', () => {
const { container } = await render(
<ChampionsInfo championService={championService} />,
);
const aatroxImage = await findByTestId(container, 'aatrox-image');
fireEvent.click(aatroxImage);
const info = await findByTestId(container, 'info');
expect(info.textContent).toEqual(aatrox.info);
});
Implement
export const ChampionsInfo: React.FC<ChampionsInfoProps> = ({ championService }) => {
const [champions, setChampions] = useState([] as Champion[]);
useEffect(() => {
championService.getChampions().then(setChampions);
}, [championService]);
return (
<div className="ChampionsInfo">
<ChampionSelector champions={champions} onSelect={() => {}} />
</div>
);
};
it('should load a champions list when the component is displayed', async () => { ... });
it('should select a champion and display the info', async () => {
const { container } = await render(
<ChampionsInfo championService={championService} />,
);
const aatroxImage = await findByTestId(container, 'aatrox-image');
fireEvent.click(aatroxImage);
const info = await findByTestId(container, 'info');
expect(info.textContent).toEqual(aatrox.info);
});
export const ChampionsInfo: React.FC<ChampionsInfoProps> = ({ championService }) => {
const [champions, setChampions] = useState([] as Champion[]);
useEffect(() => {
championService.getChampions().then(setChampions);
}, [championService]);
const [selectedChampion, setSelectedChampion] = useState({} as Champion);
const selectChampion = (championId: ChampionId) => {
const foundChampion = champions.find((champion) => championId === champion.id);
setSelectedChampion(foundChampion ? foundChampion : ({} as Champion));
};
return (
<div className="ChampionsInfo">
<ChampionSelector champions={champions} onSelect={selectChampion} />
{selectedChampion && <ChampionCard champion={selectedChampion} />}
</div>
);
};
Black box
And if we use Redux or Providers?
it('should load a champions list when the component is displayed', async () => { ... });
it('should select a champion and display the info', () => {
const { container } = await render(
<ChampionsInfo championService={championService} />,
);
const aatroxImage = await findByTestId(container, 'aatrox-image');
fireEvent.click(aatroxImage);
const info = await findByTestId(container, 'info');
expect(info.textContent).toEqual(aatrox.info);
});
it('should load a champions list when the component is displayed', async () => { ... });
it('should select a champion and display the info', () => {
const stote = createAMockStore(championService);
const { container } = await render(
<Provider store={store}>
<ChampionsInfoConnected />
</Provider>,
);
const aatroxImage = await findByTestId(container, 'aatrox-image');
fireEvent.click(aatroxImage);
const info = await findByTestId(container, 'info');
expect(info.textContent).toEqual(aatrox.info);
});
Create builder with services and state
Connect to redux
Wrapp the element
Black box
What happen with bugs?
If we found a bug when we are coding
We should create a new cases reproduce it
And then fix it
Black box
Conclusions
- Postpone decisions
- Economic tests for real cases
- Check the integration
Posible or Imposible?
Conclusions
- It's posible
- Is efficent
- Powerfull tool
- Easy for other developers
Positive
Negative
- Require knowledge
- Require practice
If you love code,
this is for you
If you hate practice...
this will be difficult to you
Questions?
Thank you!!
Test Driven Development
By afergon
Test Driven Development
- 559