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
- 750