Usuwanie danych
Załóżmy, że testujesz przypadek: formularz jest wypełniony danymi i potrzebujesz przed sprawdzeniem testu, wyczyścić daną kontrolkę. Jak to zrobić?
Komponent:
import {useState} from "react";
export function MyComponent({ userName }: { userName: string}) {
const [name, setName] = useState(userName);
const onInputChange = e => {
setName(e.target.value);
}
return (
<>
{ name &&
<div>
Hello {name}! How are you?
</div>
}
<div>
<label htmlFor="name">Your name:</label>
<input value={name} id="name" name="name" onChange={onInputChange} />
</div>
</>
)
}
Test:
import {render, screen} from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import {MyComponent} from "./MyComponent";
test('should edit user name', async () => {
render(<MyComponent userName="Iwona" />);
const input = getByDisplayValue('Iwona');
await userEvent.clear(input);
await userEvent.type(input, 'Adam');
expect(getByText('Hello Adam! How are you?')).toBeInTheDocument();
});
Na starcie przekazywana jest wartość do komponentu, która jest przypisana jest do kontrolki.
Żeby wprowadzić nową wartość, musimy kontrolkę wyczyścić. Robi się to za pomocą metody: clear z biblioteki: user-event. Jeśli zakomentujesz tę linijkę wartość kontrolki po wywołaniu metody: type będzie: "IwonaAdam".
Czym jest Closure w Swift?
Closure w Swift to funkcja, która nie posiada nazwy.
let myFunction = {
print("Hello!")
}
myFunction()
Składnia Closure
Składnia prezentuje się następująco:
{ (parameters) -> returnType in
...
}
Tak jak w "zwykłej" funkcji, ta typu Closure może posiadać parametry i możesz określić zwracany typ danych.
let calculate = { (a: Int, b: Int) -> Int in
return a + b
}
print(calculate(4, 3))
Zauważ, że w momencie wywołania funkcji typu Closure nie musimy podawać nazw parametrów, tak ja w "zwykłej" funkcji:
func substract(a: Int, b: Int) -> Int {
return a - b
}
let add = { (a: Int, b: Int) -> Int in
return a + b
}
print(add(4, 3))
print(substract(a: 10, b: 3))
print(substract(10, 3))
Closure jako parametr funkcji
Możesz przekazać do funkcji inną funkcję, która jest typu Closure:
let substract = { (a: Int, b: Int) -> Int in
return a - b
}
let add = { (a: Int, b: Int) -> Int in
return a + b
}
func calculate(a: Int, b: Int, operate: (_ a: Int, _ b: Int) -> (Int)) -> Int {
return operate(a, b);
}
print(calculate(a: 5, b: 5, operate: add))
print(calculate(a: 5, b: 5, operate: substract))
Trailing Closure
Jeśli funkcja przyjmuje kilka parametrów i ostatnim z nich jest Closure można wywołać ją w inny sposób.
"Standardowa" wersja:
func calculate(a: Int, b: Int, operate: (_ a: Int, _ b: Int) -> (Int)) -> Int {
return operate(a, b);
}
let result = calculate(a: 5, b: 5, operate: { (a: Int, b: Int) -> Int in
return a + b
})
print(result)
Można wywołać to też tak:
let result = calculate(a: 5, b: 5) { (a, b) in
return a + b
}
print(result)
Takie wywołanie nazwy się trailing closure.
Uproszczona składnia
Poniżej znajdziesz kilka sposobów wywołania Closure.
func calculate(a: Int, b: Int, operate: (_ a: Int, _ b: Int) -> (Int)) -> Int {
return operate(a, b);
}
Przykłady wywołania Closure:
calculate(a: 5, b: 5, operate: { (a: Int, b: Int) -> Int in
return a + b
})
Można krócej:
calculate(a: 5, b: 5) { (a, b) in
return a + b
}
Inna wersja:
calculate(a: 5, b: 5) {
a, b in a + b
}
Jeszcze prostsza wersja:
calculate(a: 5, b: 5) {
$0 + $1
}
$0 i $1 to referencje do parametrów Closure.
Uwaga! Można jeszcze to zapisać jeszcze inaczej:
calculate(a: 5, b: 5, operate: +)
Testowanie wprowadzenia danych
Kiedy potrzebujesz stestować komponent, w którym zachodzą interakcje z użytkownikiem, warto napisać test, który zasymuluje cały proces, tak jakby robił to użytkownik. Możesz to zrobić za pomocą biblioteki user-event
Przykład
Komponent:
export function MyComponent() {
const [name, setName] = useState('');
const onInputChange = e => {
setName(e.target.value);
}
return (
<>
{ name &&
<div>
Hello {name}! How are you?
</div>
}
<div>
<label htmlFor="name">Your name:</label>
<input value={name} id="name" name="name" onChange={onInputChange} />
</div>
</>
)
}
Kiedy użytkownik wpisze jakieś dane w pole tekstowe, na ekranie wyświetlony zostanie tekst.
Jak to przetestować?
import {render, screen} from '@testing-library/react';
import userEvent from '@testing-library/user-event';
const { getByLabelText, getByText } = screen;
test('should display greeting', async () => {
render(<MyComponent />);
const inputName = getByLabelText('Your name:');
await userEvent.type(inputName, 'Kacper');
expect(getByText('Hello Kacper! How are you?')).toBeInTheDocument();
});
Za pomocą getByLabelText i getByText pobieramy referencje do pola tekstowego i miejsca, gdzie tekst ma się wyświetlić po wpisaniu danych.
Za pomocą type z biblioteki user-event wprowadzany jest tekst do pola tekstowego. Pierwszy argument to referencja do kontrolki, dla której wpisujemy dane. Drugi argument to tekst, który chcemy przekazać.