Mockito - test controllera - nieprawidłowa liczba elementów listy

Mockito - test controllera - nieprawidłowa liczba elementów listy
B1
  • Rejestracja:ponad 2 lata
  • Ostatnio:10 miesięcy
  • Postów:24
0

Hej,

Uczę się robienia testów aplikacji z wykorzystaniem JUnit i Mockito. Próbuję zrobić test controllera przy pomocy mockMvc, ale nie mogę dojść do tego co jest nie tak.
Daje mocka na repozytorium, zeby zwracało listę z 1 elementem. Ale w teście nieważne co bym zrobił dostaję odpowiedź 200 - ok, ale lista jest pusta.

TicketRepository -> zwkle repo rezszerzone o jpaRepository. Testuje metode findAll() -> standardowa
Ticket -> ma 3 pola, gettery, settery
TicketController -> obsługa metody get i wywołanie w niej metody findAll() z TicketRepository -> najprostsze jakie może być

Sprawdziłem asercją samą metodę repozytorium po zamockowaniu i zwraca poprawnie ten 1 ticket, który zapodałem.
Jak użyję mockMvc do testu controllera, który pod adresem ".../tickets" wywołuje tylko metodę findAll() z TicketRepository.
Co robię źle, że lista w teście jest pusta, a powinna mieć jeden element?

Test wygląda następująco:

Kopiuj
package com.AplikacjaKinowa.AplikacjaKinowa.service;

import com.AplikacjaKinowa.AplikacjaKinowa.controller.TicketController;
import com.AplikacjaKinowa.AplikacjaKinowa.model.Ticket;
import com.AplikacjaKinowa.AplikacjaKinowa.model.TicketRepository;
import org.junit.Before;
import org.junit.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.MockitoJUnitRunner;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import java.util.ArrayList;
import java.util.List;
import static org.hamcrest.Matchers.hasSize;
import static org.mockito.BDDMockito.given;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@RunWith(MockitoJUnitRunner.class)
@ExtendWith(MockitoExtension.class)
public class TicketControllerMvcTest {
    private MockMvc mockMvc;

    @Autowired
    private WebApplicationContext context;

    @Mock
    TicketRepository ticketRepository;

    @InjectMocks
    TicketController ticketController;


    @Before
    public void setUp()
    {
        MockitoAnnotations.initMocks(this);
        this.mockMvc = MockMvcBuilders.standaloneSetup(ticketController).build();
    }

    @Test
    public void getTicketTest() throws Exception
    {
        Ticket ticket = new Ticket();
        ticket.setId(1);
        ticket.setPrice(111);
        ticket.setTicketType("BILECIK DO KONTROLI");


        List<Ticket> ticketList = new ArrayList<>();
        ticketList.add(ticket);
        given(ticketRepository.findAll()).willReturn(ticketList);


        MvcResult result = mockMvc.perform(get("/tickets").content(MediaType.APPLICATION_JSON_VALUE))
                .andExpect(status().isOk())
                .andExpect(MockMvcResultMatchers.jsonPath("$", hasSize(1)))
                .andReturn();

        String resultContent = result.getResponse().getContentAsString();
        System.out.println("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX: "+resultContent);

    }
}

No i dostaję po odpaleniu testu coś takiego:

Kopiuj
10:36:12.213 [main] DEBUG org.jboss.logging - Logging Provider: org.jboss.logging.Log4j2LoggerProvider
10:36:12.216 [main] INFO org.hibernate.validator.internal.util.Version - HV000001: Hibernate Validator 6.1.5.Final
10:36:12.238 [main] DEBUG org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator - Loaded expression factory via original TCCL
10:36:12.239 [main] DEBUG org.hibernate.validator.internal.engine.AbstractConfigurationImpl - Setting custom MessageInterpolator of type org.springframework.validation.beanvalidation.LocaleContextMessageInterpolator
10:36:12.240 [main] DEBUG org.hibernate.validator.internal.engine.AbstractConfigurationImpl - Setting custom ParameterNameProvider of type org.springframework.validation.beanvalidation.LocalValidatorFactoryBean$1
10:36:12.245 [main] DEBUG org.hibernate.validator.internal.xml.config.ValidationXmlParser - Trying to load META-INF/validation.xml for XML based Validator configuration.
10:36:12.246 [main] DEBUG org.hibernate.validator.internal.xml.config.ResourceLoaderHelper - Trying to load META-INF/validation.xml via TCCL
10:36:12.246 [main] DEBUG org.hibernate.validator.internal.xml.config.ResourceLoaderHelper - Trying to load META-INF/validation.xml via Hibernate Validator's class loader
10:36:12.247 [main] DEBUG org.hibernate.validator.internal.xml.config.ValidationXmlParser - No META-INF/validation.xml found. Using annotation based configuration only.
10:36:12.254 [main] DEBUG org.hibernate.validator.internal.engine.resolver.TraversableResolvers - Found javax.persistence.Persistence on classpath containing 'getPersistenceUtil'. Assuming JPA 2 environment. Trying to instantiate JPA aware TraversableResolver
10:36:12.255 [main] DEBUG org.hibernate.validator.internal.engine.resolver.TraversableResolvers - Instantiated JPA aware TraversableResolver of type org.hibernate.validator.internal.engine.resolver.JPATraversableResolver.
10:36:12.365 [main] DEBUG org.hibernate.validator.internal.engine.ValidatorFactoryConfigurationHelper - HV000252: Using org.hibernate.validator.internal.engine.DefaultPropertyNodeNameProvider as property node name provider.
10:36:12.371 [main] DEBUG org.hibernate.validator.internal.engine.ValidatorFactoryConfigurationHelper - HV000234: Using org.springframework.validation.beanvalidation.LocaleContextMessageInterpolator as ValidatorFactory-scoped message interpolator.
10:36:12.371 [main] DEBUG org.hibernate.validator.internal.engine.ValidatorFactoryConfigurationHelper - HV000234: Using org.hibernate.validator.internal.engine.resolver.JPATraversableResolver as ValidatorFactory-scoped traversable resolver.
10:36:12.371 [main] DEBUG org.hibernate.validator.internal.engine.ValidatorFactoryConfigurationHelper - HV000234: Using org.hibernate.validator.internal.util.ExecutableParameterNameProvider as ValidatorFactory-scoped parameter name provider.
10:36:12.371 [main] DEBUG org.hibernate.validator.internal.engine.ValidatorFactoryConfigurationHelper - HV000234: Using org.hibernate.validator.internal.engine.DefaultClockProvider as ValidatorFactory-scoped clock provider.
10:36:12.371 [main] DEBUG org.hibernate.validator.internal.engine.ValidatorFactoryConfigurationHelper - HV000234: Using org.hibernate.validator.internal.engine.scripting.DefaultScriptEvaluatorFactory as ValidatorFactory-scoped script evaluator factory.
10:36:12.476 [main] DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - 4 mappings in <unknown>
10:36:12.672 [main] DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter - ControllerAdvice beans: 0 @ModelAttribute, 0 @InitBinder, 1 RequestBodyAdvice, 1 ResponseBodyAdvice
10:36:12.699 [main] DEBUG org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver - ControllerAdvice beans: 0 @ExceptionHandler, 1 ResponseBodyAdvice
10:36:12.739 [main] INFO org.springframework.mock.web.MockServletContext - Initializing Spring TestDispatcherServlet ''
10:36:12.740 [main] INFO org.springframework.test.web.servlet.TestDispatcherServlet - Initializing Servlet ''
10:36:12.741 [main] DEBUG org.springframework.test.web.servlet.TestDispatcherServlet - Detected AcceptHeaderLocaleResolver
10:36:12.741 [main] DEBUG org.springframework.test.web.servlet.TestDispatcherServlet - Detected FixedThemeResolver
10:36:12.742 [main] DEBUG org.springframework.test.web.servlet.TestDispatcherServlet - Detected org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator@5e048149
10:36:12.742 [main] DEBUG org.springframework.test.web.servlet.TestDispatcherServlet - Detected org.springframework.web.servlet.support.SessionFlashMapManager@79d9214d
10:36:12.742 [main] DEBUG org.springframework.test.web.servlet.TestDispatcherServlet - enableLoggingRequestDetails='false': request parameters and headers will be masked to prevent unsafe logging of potentially sensitive data
10:36:12.742 [main] INFO org.springframework.test.web.servlet.TestDispatcherServlet - Completed initialization in 2 ms
10:36:12.783 [main] DEBUG org.springframework.test.web.servlet.TestDispatcherServlet - GET "/tickets", parameters={}
10:36:12.786 [main] DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped to com.AplikacjaKinowa.AplikacjaKinowa.controller.TicketController#getTicket()
10:36:12.796 [main] INFO com.AplikacjaKinowa.AplikacjaKinowa.controller.TicketController - TICKETS: SHOW ALL TICKETS - GET METHOD
10:36:12.808 [main] DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor - Using 'application/json', given [*/*] and supported [application/json, application/*+json]
10:36:12.809 [main] DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor - Writing [[]]
10:36:12.823 [main] DEBUG org.springframework.test.web.servlet.TestDispatcherServlet - Completed 200 OK
10:36:12.860 [main] DEBUG com.jayway.jsonpath.internal.path.CompiledPath - Evaluating path: $

java.lang.AssertionError: JSON path "$"
Expected: a collection with size <1>
     but: collection size was <0>

	at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:18)
	at org.springframework.test.util.JsonPathExpectationsHelper.assertValue(JsonPathExpectationsHelper.java:73)
	at org.springframework.test.web.servlet.result.JsonPathResultMatchers.lambda$value$0(JsonPathResultMatchers.java:87)
	at org.springframework.test.web.servlet.MockMvc$1.andExpect(MockMvc.java:196)
	at com.AplikacjaKinowa.AplikacjaKinowa.service.TicketControllerMvcTest.getTicketTest(TicketControllerMvcTest.java:77)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:567)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
	at org.mockito.internal.runners.DefaultInternalRunner$1$1.evaluate(DefaultInternalRunner.java:46)
	at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
	at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
	at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
	at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
	at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
	at org.mockito.internal.runners.DefaultInternalRunner$1.run(DefaultInternalRunner.java:77)
	at org.mockito.internal.runners.DefaultInternalRunner.run(DefaultInternalRunner.java:83)
	at org.mockito.internal.runners.StrictRunner.run(StrictRunner.java:39)
	at org.mockito.junit.MockitoJUnitRunner.run(MockitoJUnitRunner.java:163)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)


Process finished with exit code -1

edytowany 2x, ostatnio: Riddle
Korges
Dobrze napisanego kontrolera się nie testuje jednostkowo.
Riddle
Administrator
  • Rejestracja:prawie 15 lat
  • Ostatnio:10 minut
  • Lokalizacja:Laska, z Polski
  • Postów:10059
0
Batman109 napisał(a):

Uczę się robienia testów aplikacji z wykorzystaniem JUnit i Mockito. Próbuję zrobić test controllera przy pomocy mockMvc, ale nie mogę dojść do tego co jest nie tak.

Jeśli na prawdę uczysz się pisać dopiero testy automatyczne, to rozpoczęcie tej nauki o testów aplikacji springowych z JPA to jest najtrudniejsza i najgorsza rzecz jaką możesz zrobić.

Zacznij napisanie testu o prostej aplikacji, bez springa, bez bazy, która tylko wpuszcza i wypuszcza dane. Napisz tak chociaż 30 testów, i zacznij dalszą naukę od tego.

Testy aplikacji HTTP z bazą są bardzo trudne żeby je zrobić dobrze; i bardzo prosto jest sobie wyrobić masę złych nawyków.

KamilAdam
  • Rejestracja:ponad 6 lat
  • Ostatnio:7 dni
  • Lokalizacja:Silesia/Marki
  • Postów:5505
0

Pokarz jak wygląda TicketController


Mama called me disappointment, Papa called me fat
Każdego eksperta można zastąpić backendowcem który ma się douczyć po godzinach. Tak zostałem ekspertem AI, Neo4j i Nest.js . Przez mianowanie
B1
  • Rejestracja:ponad 2 lata
  • Ostatnio:10 miesięcy
  • Postów:24
0
KamilAdam napisał(a):

Pokarz jak wygląda TicketController

Kopiuj
@RestController
@RequestMapping("/tickets")
public class TicketController {

    private final ApplicationEventPublisher eventPublisher;
    private static final Logger logger = LoggerFactory.getLogger(TicketController.class);
    private final TicketRepository ticketRepository;

    public TicketController(final ApplicationEventPublisher eventPublisher, final TicketRepository ticketRepository) {
        this.eventPublisher = eventPublisher;
        this.ticketRepository = ticketRepository;
    }

    //GET METHOD - TICKET - SMALL - TEN PRZYPADEK TESTUJE!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    @GetMapping()
    public List<Ticket> getTicket()
    {
        logger.info("TICKETS: SHOW ALL TICKETS - GET METHOD");
        return ticketRepository.findAll();
    }
}
edytowany 1x, ostatnio: Riddle
Riddle
Administrator
  • Rejestracja:prawie 15 lat
  • Ostatnio:10 minut
  • Lokalizacja:Laska, z Polski
  • Postów:10059
1

Ten controller nie ma w sobie logiki nie ma tutaj co testować.

Jeśli chcesz napisać dobry test, to powinieneś zrobić test który strzela pod dwa endpointy, coś w stylu

(pseudokod)

Kopiuj
post("/ticket", singletonMap("name", "mój ticket"));
ticket = get("/ticket/1");
assertEquals("mój ticket", ticket.name);

I sugerowałbym bez mockito, tylko np wbudowany test client od springa i h2 albo baza in-memory.

edytowany 3x, ostatnio: Riddle
B1
  • Rejestracja:ponad 2 lata
  • Ostatnio:10 miesięcy
  • Postów:24
0
Riddle napisał(a):

Ten controller nie ma w sobie logiki nie ma tutaj co testować.

Jeśli chcesz napisać dobry test, to powinieneś zrobić test który strzela pod dwa endpointy, coś w stylu

(pseudokod)

Kopiuj
post("/ticket", singletonMap("name", "mój ticket"));
ticket = get("/ticket/1");
assertEquals("mój ticket", ticket.name);

Tak ja wiem, że nic takiego nie ma w nim.
Zrobiłem wcześniej parę testów i chciałem zobaczyć pierwszy raz jak to działa z mockmvc, nie działało więc wybrałem sobie najprostszy przypadek gdzie oprę się o przykłady w internetowych tutorialach i gdzie teoretycznie nic się nie powinno rozkraczyć.

Chciałbym zrozumieć co się dzieje, że tam w teście zwraca mi listę z zerową liczbą elementów. Bo dla mnie ten kod wygląda logicznie i nie bardzo rozumiem to zachowanie.

Riddle
Administrator
  • Rejestracja:prawie 15 lat
  • Ostatnio:10 minut
  • Lokalizacja:Laska, z Polski
  • Postów:10059
0
Batman109 napisał(a):

Tak ja wiem, że nic takiego nie ma w nim.
Zrobiłem wcześniej parę testów i chciałem zobaczyć pierwszy raz jak to działa z mockmvc, nie działało więc wybrałem sobie najprostszy przypadek gdzie oprę się o przykłady w internetowych tutorialach i gdzie teoretycznie nic się nie powinno rozkraczyć.

Chciałbym zrozumieć co się dzieje, że tam w teście zwraca mi listę z zerową liczbą elementów. Bo dla mnie ten kod wygląda logicznie i nie bardzo rozumiem to zachowanie.

Wybrałeś sobie średnio dobry punkt żeby zacząć, bo mockmvc ze springa to nie jest dobry przykład tego jak powinno się pisać takie testy. Dużo lepiej byłoby gdybyś zaczął od pisania testów do prostych programów, takich które nie mają tyle boundries jak aplikacje webowe.

Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)