website/docs/help/dev/index.html

17 lines
37 KiB
HTML
Raw Permalink Blame History

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

<!doctype html>
<html lang="en" dir="ltr" class="docs-wrapper docs-doc-page docs-version-current plugin-docs plugin-id-default docs-doc-id-dev/index" data-has-hydrated="false">
<head>
<meta charset="UTF-8">
<meta name="generator" content="Docusaurus v2.4.3">
<title data-rh="true">Contributing to Joplin | Joplin</title><meta data-rh="true" name="viewport" content="width=device-width,initial-scale=1"><meta data-rh="true" name="twitter:card" content="summary_large_image"><meta data-rh="true" property="og:url" content="https://joplinapp.org/help/dev/"><meta data-rh="true" name="docusaurus_locale" content="en"><meta data-rh="true" name="docsearch:language" content="en"><meta data-rh="true" name="docusaurus_version" content="current"><meta data-rh="true" name="docusaurus_tag" content="docs-default-current"><meta data-rh="true" name="docsearch:version" content="current"><meta data-rh="true" name="docsearch:docusaurus_tag" content="docs-default-current"><meta data-rh="true" property="og:title" content="Contributing to Joplin | Joplin"><meta data-rh="true" name="description" content="User support The Joplin Forum is the community driven place for user support, general discussion about Joplin, problems with installation, new features and software development questions. It is pos..."><meta data-rh="true" property="og:description" content="User support The Joplin Forum is the community driven place for user support, general discussion about Joplin, problems with installation, new features and software development questions. It is pos..."><link data-rh="true" rel="icon" href="https://joplinapp.org/favicon.ico"><link data-rh="true" rel="canonical" href="https://joplinapp.org/help/dev/"><link data-rh="true" rel="alternate" href="https://joplinapp.org/help/dev/" hreflang="en"><link data-rh="true" rel="alternate" href="https://joplinapp.org/fr/help/dev/" hreflang="fr"><link data-rh="true" rel="alternate" href="https://joplinapp.org/help/dev/" hreflang="x-default"><link rel="alternate" type="application/rss+xml" href="/news/rss.xml" title="Joplin RSS Feed">
<link rel="alternate" type="application/atom+xml" href="/news/atom.xml" title="Joplin Atom Feed"><link rel="stylesheet" href="/assets/css/styles.3f0207fa.css">
<link rel="preload" href="/assets/js/runtime~main.1fb4f966.js" as="script">
<link rel="preload" href="/assets/js/main.aa9faae4.js" as="script">
</head>
<body class="navigation-with-keyboard">
<script>!function(){function t(t){document.documentElement.setAttribute("data-theme",t)}var e=function(){var t=null;try{t=new URLSearchParams(window.location.search).get("docusaurus-theme")}catch(t){}return t}()||function(){var t=null;try{t=localStorage.getItem("theme")}catch(t){}return t}();t(null!==e?e:"light")}()</script><div id="__docusaurus">
<div role="region" aria-label="Skip to main content"><a class="skipToContent_fXgn" href="#__docusaurus_skipToContent_fallback">Skip to main content</a></div><nav aria-label="Main" class="navbar navbar--fixed-top"><div class="navbar__inner"><div class="navbar__items"><button aria-label="Toggle navigation bar" aria-expanded="false" class="navbar__toggle clean-btn" type="button"><svg width="30" height="30" viewBox="0 0 30 30" aria-hidden="true"><path stroke="currentColor" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2" d="M4 7h22M4 15h22M4 23h22"></path></svg></button><a href="https://joplinapp.org" target="_self" rel="noopener noreferrer" class="navbar__brand"><div class="navbar__logo"><img src="/images/logo-text-blue.svg" alt="Joplin" class="themedImage_ToTc themedImage--light_HNdA"><img src="/images/logo-text-blue.svg" alt="Joplin" class="themedImage_ToTc themedImage--dark_i4oU"></div><b class="navbar__title text--truncate"></b></a></div><div class="navbar__items navbar__items--right"><a class="navbar__item navbar__link" href="/news">News</a><a aria-current="page" class="navbar__item navbar__link navbar__link--active" href="/help/">Help</a><a href="https://discourse.joplinapp.org" target="_blank" rel="noopener noreferrer" class="navbar__item navbar__link">Forum</a><a href="https://joplinapp.org/plans" target="_self" rel="noopener noreferrer" class="navbar__item navbar__link navbar-custom-buttons plans-button">Joplin Cloud</a><a href="https://joplinapp.org/donate" target="_self" rel="noopener noreferrer" class="navbar__item navbar__link navbar-custom-buttons sponsor-button">♡ Support us</a><div class="navbar__item dropdown dropdown--hoverable dropdown--right"><a href="#" aria-haspopup="true" aria-expanded="false" role="button" class="navbar__link"><svg viewBox="0 0 24 24" width="20" height="20" aria-hidden="true" class="iconLanguage_nlXk"><path fill="currentColor" d="M12.87 15.07l-2.54-2.51.03-.03c1.74-1.94 2.98-4.17 3.71-6.53H17V4h-7V2H8v2H1v1.99h11.17C11.5 7.92 10.44 9.75 9 11.35 8.07 10.32 7.3 9.19 6.69 8h-2c.73 1.63 1.73 3.17 2.98 4.56l-5.09 5.02L4 19l5-5 3.11 3.11.76-2.04zM18.5 10h-2L12 22h2l1.12-3h4.75L21 22h2l-4.5-12zm-2.62 7l1.62-4.33L19.12 17h-3.24z"></path></svg>English</a><ul class="dropdown__menu"><li><a href="/help/dev/" target="_self" rel="noopener noreferrer" class="dropdown__link dropdown__link--active" lang="en">English</a></li><li><a href="/fr/help/dev/" target="_self" rel="noopener noreferrer" class="dropdown__link" lang="fr">Français</a></li></ul></div><div class="toggle_vylO colorModeToggle_DEke"><button class="clean-btn toggleButton_gllP toggleButtonDisabled_aARS" type="button" disabled="" title="Switch between dark and light mode (currently light mode)" aria-label="Switch between dark and light mode (currently light mode)" aria-live="polite"><svg viewBox="0 0 24 24" width="24" height="24" class="lightToggleIcon_pyhR"><path fill="currentColor" d="M12,9c1.65,0,3,1.35,3,3s-1.35,3-3,3s-3-1.35-3-3S10.35,9,12,9 M12,7c-2.76,0-5,2.24-5,5s2.24,5,5,5s5-2.24,5-5 S14.76,7,12,7L12,7z M2,13l2,0c0.55,0,1-0.45,1-1s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S1.45,13,2,13z M20,13l2,0c0.55,0,1-0.45,1-1 s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S19.45,13,20,13z M11,2v2c0,0.55,0.45,1,1,1s1-0.45,1-1V2c0-0.55-0.45-1-1-1S11,1.45,11,2z M11,20v2c0,0.55,0.45,1,1,1s1-0.45,1-1v-2c0-0.55-0.45-1-1-1C11.45,19,11,19.45,11,20z M5.99,4.58c-0.39-0.39-1.03-0.39-1.41,0 c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0s0.39-1.03,0-1.41L5.99,4.58z M18.36,16.95 c-0.39-0.39-1.03-0.39-1.41,0c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0c0.39-0.39,0.39-1.03,0-1.41 L18.36,16.95z M19.42,5.99c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06c-0.39,0.39-0.39,1.03,0,1.41 s1.03,0.39,1.41,0L19.42,5.99z M7.05,18.36c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06 c-0.39,0.39-0.39,1.03,0,1.41s1.03,0.39,1.41,0L7.05,18.36z"></path></svg><svg viewBox="0 0 24 24" width="24" height="24" class="darkToggleIcon_wfgR"><path fill="currentColor" d="M9.37,5.51C9.19,6.15,9.1,6.82,9.1,7.5c0,4.08,3.32,7.4,7.4,7.4c0.68,0,1.35-0.09,1.99-0.27C17.45,17.19,14.93,19,12,19 c-3.86,0-7-3.14-7-7C5,9.07,6.81,6.55,9.37,5.51z M12,3c-4.97,0-9,4.03-9,9s4.03,9,9,9s9-4.03,9-9c0-0.46-0.04-0.92-0.1-1.36 c-0.98,1.37-2.58,2.26-4.4,2.26c-2.98,0-5.4-2.42-5.4-5.4c0-1.81,0.89-3.42,2.26-4.4C12.92,3.04,12.46,3,12,3L12,3z"></path></svg></button></div><div class="searchBox_ZlJk"><div class="navbar__search"><span aria-label="expand searchbar" role="button" class="search-icon" tabindex="0"></span><input type="search" id="search_input_react" placeholder="Loading..." aria-label="Search" class="navbar__search-input search-bar" disabled=""></div></div></div></div><div role="presentation" class="navbar-sidebar__backdrop"></div></nav><div id="__docusaurus_skipToContent_fallback" class="main-wrapper mainWrapper_z2l0 docsWrapper_BCFX"><button aria-label="Scroll back to top" class="clean-btn theme-back-to-top-button backToTopButton_sjWU" type="button"></button><div class="docPage__5DB"><aside class="theme-doc-sidebar-container docSidebarContainer_b6E3"><div class="sidebarViewport_Xe31"><div class="sidebar_njMd"><nav aria-label="Docs sidebar" class="menu thin-scrollbar menu_SIkG"><ul class="theme-doc-sidebar-menu menu__list"><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-1 menu__list-item"><a class="menu__link" href="/help/">What is Joplin?</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-1 menu__list-item"><a class="menu__link" href="/help/install">Installation</a></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item menu__list-item--collapsed"><div class="menu__list-item-collapsible"><a class="menu__link menu__link--sublist" aria-expanded="false" href="/help/apps/">Using Joplin</a><button aria-label="Toggle the collapsible sidebar category &#x27;Using Joplin&#x27;" type="button" class="clean-btn menu__caret"></button></div></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item menu__list-item--collapsed"><div class="menu__list-item-collapsible"><a class="menu__link menu__link--sublist" aria-expanded="false" href="/help/api/">Programmatic API</a><button aria-label="Toggle the collapsible sidebar category &#x27;Programmatic API&#x27;" type="button" class="clean-btn menu__caret"></button></div></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item"><div class="menu__list-item-collapsible menu__list-item-collapsible--active"><a class="menu__link menu__link--sublist menu__link--active" aria-current="page" aria-expanded="true" href="/help/dev/">Development</a><button aria-label="Toggle the collapsible sidebar category &#x27;Development&#x27;" type="button" class="clean-btn menu__caret"></button></div><ul style="display:block;overflow:visible;height:auto" class="menu__list"><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-2 menu__list-item menu__list-item--collapsed"><div class="menu__list-item-collapsible"><a class="menu__link menu__link--sublist menu__link--sublist-caret" aria-expanded="false" tabindex="0" href="/help/dev/spec/architecture">Technical specifications</a></div></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-2 menu__list-item menu__list-item--collapsed"><div class="menu__list-item-collapsible"><a class="menu__link menu__link--sublist menu__link--sublist-caret" aria-expanded="false" tabindex="0" href="/help/dev/gsoc/gsoc2020/">Google Summer of Code</a></div></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/help/dev/BUILD">Building the applications</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/help/dev/DEPLOY">Deploying Joplin apps and scripts</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/help/dev/build_troubleshooting">Build troubleshooting</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/help/dev/coding_style">Coding style</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/help/dev/localisation">Localisation</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/help/dev/spellcheck">Spellchecking using CSpell</a></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-2 menu__list-item"><a class="menu__link" tabindex="0" href="/help/dev/technical_spec">Guide to writing a technical spec</a></li></ul></li><li class="theme-doc-sidebar-item-category theme-doc-sidebar-item-category-level-1 menu__list-item menu__list-item--collapsed"><div class="menu__list-item-collapsible"><a class="menu__link menu__link--sublist menu__link--sublist-caret" aria-expanded="false" href="/help/about/changelog/android">About</a></div></li><li class="theme-doc-sidebar-item-link theme-doc-sidebar-item-link-level-1 menu__list-item"><a class="menu__link" href="/help/faq">FAQ</a></li></ul></nav></div></div></aside><main class="docMainContainer_gTbr"><div class="container padding-top--md padding-bottom--lg"><div class="row"><div class="col docItemCol_VOVn"><div class="docItemContainer_Djhp"><article><div class="tocCollapsible_ETCw theme-doc-toc-mobile tocMobile_ITEo"><button type="button" class="clean-btn tocCollapsibleButton_TO0P">On this page</button></div><div class="theme-doc-markdown markdown"><h1>Contributing to Joplin</h1><div class="donate-links"><p><a href="https://www.paypal.com/donate/?business=E8JMYD2LQ8MMA&amp;no_recurring=0&amp;item_name=I+rely+on+donations+to+maintain+and+improve+the+Joplin+open+source+project.+Thank+you+for+your+help+-+it+makes+a+difference%21&amp;currency_code=EUR" target="_blank" rel="noopener noreferrer"><img loading="lazy" src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/badges/Donate-PayPal-green.svg" alt="Donate using PayPal" class="img_ev3q"></a> <a href="https://github.com/sponsors/laurent22/" target="_blank" rel="noopener noreferrer"><img loading="lazy" src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/badges/GitHub-Badge.svg" alt="Sponsor on GitHub" class="img_ev3q"></a> <a href="https://www.patreon.com/joplin" target="_blank" rel="noopener noreferrer"><img loading="lazy" src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/badges/Patreon-Badge.svg" alt="Become a patron" class="img_ev3q"></a> <a href="https://joplinapp.org/donate/#donations" target="_blank" rel="noopener noreferrer"><img loading="lazy" src="https://raw.githubusercontent.com/laurent22/joplin/dev/Assets/WebsiteAssets/images/badges/Donate-IBAN.svg" alt="Donate using IBAN" class="img_ev3q"></a></p></div><h2 class="anchor anchorWithStickyNavbar_LWe7" id="user-support">User support<a href="#user-support" class="hash-link" aria-label="Direct link to User support" title="Direct link to User support"></a></h2><p>The <a href="https://discourse.joplinapp.org/" target="_blank" rel="noopener noreferrer">Joplin Forum</a> is the community driven place for user support, general discussion about Joplin, problems with installation, new features and software development questions. It is possible to login with your GitHub account. Don&#x27;t use the issue tracker for support questions.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="reporting-a-bug">Reporting a bug<a href="#reporting-a-bug" class="hash-link" aria-label="Direct link to Reporting a bug" title="Direct link to Reporting a bug"></a></h2><p>File bugs in the <a href="https://github.com/laurent22/joplin/issues?utf8=%E2%9C%93&amp;q=is%3Aissue" target="_blank" rel="noopener noreferrer">Github Issue Tracker</a>. Please follow these guidelines:</p><ul><li>Search existing issues first, make sure yours hasn&#x27;t already been reported.</li><li>Please follow the template.</li><li>Consider <a href="https://joplinapp.org/help/apps/debugging/" target="_blank" rel="noopener noreferrer">enabling debug mode</a> so that you can provide as much details as possible when reporting the issue.</li><li>Stay on topic, but describe the issue in detail so that others can <strong>reproduce</strong> it.</li><li><strong>Provide a screenshot</strong> if possible. A screenshot showing the problem is often more useful than a paragraph describing it.</li><li>For web clipper bugs, <strong>please provide the URL causing the issue</strong>. Sometimes the clipper works in one page but not in another so it is important to know what URL has a problem.</li></ul><h2 class="anchor anchorWithStickyNavbar_LWe7" id="feature-requests">Feature requests<a href="#feature-requests" class="hash-link" aria-label="Direct link to Feature requests" title="Direct link to Feature requests"></a></h2><p>Feature requests <strong>must be opened and discussed on the <a href="https://discourse.joplinapp.org/c/features" target="_blank" rel="noopener noreferrer">forum</a></strong>. After they have been accepted, they can be added to the GitHub tracker.</p><p>Please check that your request has not already been posted on the forum or the <a href="https://github.com/laurent22/joplin/issues?utf8=%E2%9C%93&amp;q=is%3Aissue" target="_blank" rel="noopener noreferrer">Github Issue Tracker</a>. If it has, <strong>up-voting the issue or topic</strong> increases the chances it&#x27;ll be noticed and implemented in the future. &quot;+1&quot; comments are not tracked.</p><p>Avoid listing multiple requests in one topic. One topic per request makes it easier to track and discuss it.</p><p>Finally, when submitting a pull request, don&#x27;t forget to <a href="#automated-tests">test your code</a>.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="contributing-to-joplins-translation">Contributing to Joplin&#x27;s translation<a href="#contributing-to-joplins-translation" class="hash-link" aria-label="Direct link to Contributing to Joplin&#x27;s translation" title="Direct link to Contributing to Joplin&#x27;s translation"></a></h2><p>Joplin is available in multiple languages thanks to the help of its users. You can help translate Joplin to your language or keep it up to date. Please read the documentation about <a href="https://joplinapp.org/help/dev/localisation" target="_blank" rel="noopener noreferrer">Localisation</a>.</p><h2 class="anchor anchorWithStickyNavbar_LWe7" id="contributing-to-joplins-code">Contributing to Joplin&#x27;s code<a href="#contributing-to-joplins-code" class="hash-link" aria-label="Direct link to Contributing to Joplin&#x27;s code" title="Direct link to Contributing to Joplin&#x27;s code"></a></h2><p>If you want to start contributing to the project&#x27;s code, please follow these guidelines before creating a pull request:</p><ul><li>The top post of the pull request should contain a full, self-contained explanation of the feature: what it does, how it does it, with examples of usage and screenshots. Also explain why you want to add this - what problem does it solve. Do not simply add a text <code>Implement feature #4345</code> or link to forum posts, because the information there will most likely be outdated or confusing (multiple discussions and opinions). The pull request needs to be self-contained.</li><li>Bug fixes are always welcome. Start by reviewing the <a href="https://github.com/laurent22/joplin/issues?q=is%3Aissue+is%3Aopen+label%3Abug" target="_blank" rel="noopener noreferrer">list of bugs</a></li><li>A good way to easily start contributing is to pick and work on a <a href="https://github.com/laurent22/joplin/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22" target="_blank" rel="noopener noreferrer">good first issue</a>. We try to make these issues as clear as possible and provide basic info on how the code should be changed, and if something is unclear feel free to ask for more information on the issue.</li><li>Before adding a new feature, ask about it in the <a href="https://github.com/laurent22/joplin/issues?utf8=%E2%9C%93&amp;q=is%3Aissue" target="_blank" rel="noopener noreferrer">Github Issue Tracker</a> or the <a href="https://discourse.joplinapp.org/" target="_blank" rel="noopener noreferrer">Joplin Forum</a>, or check if existing discussions exist to make sure the new functionality is desired.</li><li><strong>Changes that will consist of more than 50 lines of code should be discussed on the <a href="https://discourse.joplinapp.org/" target="_blank" rel="noopener noreferrer">Joplin Forum</a></strong>, so that you don&#x27;t spend too much time implementing something that might not be accepted.</li><li>All the applications share the same backend (database, synchronisation, settings, models, business logic, etc.) so if you change something in the backend in one app, make sure it still works in the other apps. Usually it does, but keep this in mind.</li><li>Pull requests that make many changes using an automated tool, like for spell fixing, styling, etc. will not be accepted. An exception would be if the changes have been discussed in the forum and someone has agreed to review <strong>and test</strong> the pull request.</li><li>Pull requests that address multiple issues will most likely stall and eventually be closed. This is because we might be fine with one of the changes but not with others and untangling that kind of pull request is too much hassle both for maintainers and the person who submitted it. So most of the time someone gives up and the PR gets closed. So please keep the pull request focused on one issue.</li><li><strong>Do not mark your reviewer&#x27;s comments as &quot;resolved&quot;</strong>. If you do that, the comments will be hidden and the reviewer will not know what are the pending issues in the pull request. Only the reviewer should resolve the comments.</li></ul><p>Building the apps is relatively easy - please <a href="/help/dev/BUILD">see the build instructions</a> for more details.</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="signing-the-individual-contributor-license-agreement">Signing the Individual Contributor License Agreement<a href="#signing-the-individual-contributor-license-agreement" class="hash-link" aria-label="Direct link to Signing the Individual Contributor License Agreement" title="Direct link to Signing the Individual Contributor License Agreement"></a></h3><p>All contributors to the project must sign our <a href="https://raw.githubusercontent.com/laurent22/joplin/dev/readme/cla.md" target="_blank" rel="noopener noreferrer">Individual Contributor License Agreement</a>.</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="coding-style">Coding style<a href="#coding-style" class="hash-link" aria-label="Direct link to Coding style" title="Direct link to Coding style"></a></h3><p>Please see <a href="/help/dev/coding_style">the coding style document</a>.</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="gui-style">GUI style<a href="#gui-style" class="hash-link" aria-label="Direct link to GUI style" title="Direct link to GUI style"></a></h3><p>For changes made to the Desktop and mobile clients that affect the user interface, refer to <code>packages/lib/theme.ts</code> for all styling information. The goal is to create a consistent user interface to allow for easy navigation of Joplin&#x27;s various features and improve the overall user experience.</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="automated-tests">Automated tests<a href="#automated-tests" class="hash-link" aria-label="Direct link to Automated tests" title="Direct link to Automated tests"></a></h3><p>When submitting a pull request for a new feature or a bug fix, please add automated tests. We use <a href="https://jestjs.io/" target="_blank" rel="noopener noreferrer">Jest</a> as a testing framework so you will need to be familiar with it or go through their documentation.</p><h4 class="anchor anchorWithStickyNavbar_LWe7" id="running-the-tests">Running the tests<a href="#running-the-tests" class="hash-link" aria-label="Direct link to Running the tests" title="Direct link to Running the tests"></a></h4><p>To run all the test units, run from the root:</p><div class="language-sh codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-sh codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">yarn test</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>Or you can go inside a package folder, and run the tests from there. For example to run all the library tests, go in <code>packages/lib</code> and run <code>yarn test</code></p><p>To run just one particular file:</p><div class="language-sh codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-sh codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">## Run all the tests in markdownUtils.test.ts</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">yarn test markdownUtils</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>To run only a particular test in a file:</p><div class="language-sh codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-sh codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">## Run only the test described as &quot;should handle conflict&quot;</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">## inside markdownUtils.test.ts:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">yarn test markdownUtils --filter=&quot;should handle conflict&quot;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h4 class="anchor anchorWithStickyNavbar_LWe7" id="adding-a-new-test-file">Adding a new test file<a href="#adding-a-new-test-file" class="hash-link" aria-label="Direct link to Adding a new test file" title="Direct link to Adding a new test file"></a></h4><p>To add a test, simply create a new file with an extension <code>.test.ts</code> in the same directory. For example if you are working on the file <code>example.ts</code>, create a file <code>example.test.ts</code> for the unit tests. If this file already exist, simply add your tests directly to it.</p><h4 class="anchor anchorWithStickyNavbar_LWe7" id="setting-the-testing-environment">Setting the testing environment<a href="#setting-the-testing-environment" class="hash-link" aria-label="Direct link to Setting the testing environment" title="Direct link to Setting the testing environment"></a></h4><p>Many utility functions are available under the package <code>@joplin/lib/testing/test-utils</code>. Have a look for example at <a href="https://github.com/laurent22/joplin/blob/dev/packages/lib/models/Note.test.ts" target="_blank" rel="noopener noreferrer">Note.test.ts</a> to see how to setup test units with database support and synchroniser support. Note that this is not needed for all tests - if you just have a simple functions to test you won&#x27;t need that extra setup.</p><h4 class="anchor anchorWithStickyNavbar_LWe7" id="testing-react-hooks">Testing React Hooks<a href="#testing-react-hooks" class="hash-link" aria-label="Direct link to Testing React Hooks" title="Direct link to Testing React Hooks"></a></h4><p>To test React Hooks please use the package <code>@testing-library/react-hooks</code>. See <a href="https://github.com/laurent22/joplin/blob/dev/packages/app-desktop/gui/ResizableLayout/utils/useLayoutItemSizes.test.ts" target="_blank" rel="noopener noreferrer">useLayoutItemSizes.test.ts</a> for an example.</p><h4 class="anchor anchorWithStickyNavbar_LWe7" id="if-it-is-not-possible-to-add-tests">If it is not possible to add tests<a href="#if-it-is-not-possible-to-add-tests" class="hash-link" aria-label="Direct link to If it is not possible to add tests" title="Direct link to If it is not possible to add tests"></a></h4><p>More often than not, it is actually possible to add tests - just go back to your code and see if it can be refactored and certain functionalities moved to simple functions (with no dependencies). Once you have a simple function, you can easily add unit tests for it.</p><p>Additionally, if the unit tests are not sufficient, please provide a <strong>manual testing plan</strong>, which should include detailed steps on:</p><ul><li>How to test that your feature is working. Include at least 5 tests. Try to think of the possible inputs - if it&#x27;s a list, how does it work with 0 elements, or 1, or 10, or 100,000. If it&#x27;s a text input, how does it work with an empty string, or a very large string, etc. Basically don&#x27;t just put one test that check the best case scenario.</li><li>How to verify that related parts of the applications are not broken. For example if you changed the note loading logic, check that the toolbar is still working as expected (and not modifying the previously loaded note for example), check that switching from one note to another still works. Look at the note list and verify that the note title is updated there too, etc.</li></ul><p>A reviewer should be able to run the app with your changes, then do the above steps to verify that everything&#x27;s working as expected.</p><h3 class="anchor anchorWithStickyNavbar_LWe7" id="about-abandoned-pull-requests">About abandoned pull requests<a href="#about-abandoned-pull-requests" class="hash-link" aria-label="Direct link to About abandoned pull requests" title="Direct link to About abandoned pull requests"></a></h3><p>It happens that a pull request is started but not finished and despite our attempts to contact the contributor, we don&#x27;t hear from them again.</p><p>In that case we will not merge the pull request, even if only small changes are missing. Our policy is simply to close the pull request. Why? Because an unfinished pull request essentially means giving us work and moving on. We would rather not encourage this behaviour.</p><p>Also, please note that since we have spent time reviewing the pull request and proposing solutions, we reserve the right to re-use that knowledge to create a new pull request, potentially based on your changes.</p><p>We&#x27;d much prefer that you complete the pull request though, so we&#x27;ll be sure to ping you a few times before that!</p></div><footer class="theme-doc-footer docusaurus-mt-lg"><div class="theme-doc-footer-edit-meta-row row"><div class="col"><a href="https://github.com/laurent22/joplin/tree/dev/readme/dev/index.md" target="_blank" rel="noreferrer noopener" class="theme-edit-this-page"><svg fill="currentColor" height="20" width="20" viewBox="0 0 40 40" class="iconEdit_Z9Sw" aria-hidden="true"><g><path d="m34.5 11.7l-3 3.1-6.3-6.3 3.1-3q0.5-0.5 1.2-0.5t1.1 0.5l3.9 3.9q0.5 0.4 0.5 1.1t-0.5 1.2z m-29.5 17.1l18.4-18.5 6.3 6.3-18.4 18.4h-6.3v-6.2z"></path></g></svg>Edit this page</a></div><div class="col lastUpdated_vwxv"></div></div></footer></article><nav class="pagination-nav docusaurus-mt-lg" aria-label="Docs pages"><a class="pagination-nav__link pagination-nav__link--prev" href="/help/api/references/plugin_theming"><div class="pagination-nav__sublabel">Previous</div><div class="pagination-nav__label">Plugin theming</div></a><a class="pagination-nav__link pagination-nav__link--next" href="/help/dev/spec/architecture"><div class="pagination-nav__sublabel">Next</div><div class="pagination-nav__label">Joplin architecture</div></a></nav></div></div><div class="col col--3"><div class="tableOfContents_bqdL thin-scrollbar theme-doc-toc-desktop"><ul class="table-of-contents table-of-contents__left-border"><li><a href="#user-support" class="table-of-contents__link toc-highlight">User support</a></li><li><a href="#reporting-a-bug" class="table-of-contents__link toc-highlight">Reporting a bug</a></li><li><a href="#feature-requests" class="table-of-contents__link toc-highlight">Feature requests</a></li><li><a href="#contributing-to-joplins-translation" class="table-of-contents__link toc-highlight">Contributing to Joplin&#39;s translation</a></li><li><a href="#contributing-to-joplins-code" class="table-of-contents__link toc-highlight">Contributing to Joplin&#39;s code</a><ul><li><a href="#signing-the-individual-contributor-license-agreement" class="table-of-contents__link toc-highlight">Signing the Individual Contributor License Agreement</a></li><li><a href="#coding-style" class="table-of-contents__link toc-highlight">Coding style</a></li><li><a href="#gui-style" class="table-of-contents__link toc-highlight">GUI style</a></li><li><a href="#automated-tests" class="table-of-contents__link toc-highlight">Automated tests</a></li><li><a href="#about-abandoned-pull-requests" class="table-of-contents__link toc-highlight">About abandoned pull requests</a></li></ul></li></ul></div></div></div></div></main></div></div><footer class="footer footer--dark"><div class="container container-fluid"><div class="row footer__links"><div class="col footer__col"><div class="footer__title">Community</div><ul class="footer__items clean-list"><li class="footer__item"><a href="https://twitter.com/joplinapp" target="_blank" rel="noopener noreferrer" class="footer__link-item">Twitter<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_nPIU"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path></svg></a></li><li class="footer__item"><a href="https://www.patreon.com/joplin" target="_blank" rel="noopener noreferrer" class="footer__link-item">Patreon<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_nPIU"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path></svg></a></li><li class="footer__item"><a href="https://www.linkedin.com/company/joplin" target="_blank" rel="noopener noreferrer" class="footer__link-item">LinkedIn<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_nPIU"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path></svg></a></li><li class="footer__item"><a href="https://discord.gg/VSj7AFHvpq" target="_blank" rel="noopener noreferrer" class="footer__link-item">Discord<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_nPIU"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path></svg></a></li><li class="footer__item"><a href="https://mastodon.social/@joplinapp" target="_blank" rel="noopener noreferrer" class="footer__link-item">Mastodon<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_nPIU"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path></svg></a></li><li class="footer__item"><a href="https://sopuli.xyz/c/joplinapp" target="_blank" rel="noopener noreferrer" class="footer__link-item">Lemmy<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_nPIU"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path></svg></a></li><li class="footer__item"><a href="https://github.com/laurent22/joplin/" target="_blank" rel="noopener noreferrer" class="footer__link-item">GitHub<svg width="13.5" height="13.5" aria-hidden="true" viewBox="0 0 24 24" class="iconExternalLink_nPIU"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z"></path></svg></a></li></ul></div><div class="col footer__col"><div class="footer__title">Legal</div><ul class="footer__items clean-list"><li class="footer__item"><a href="https://joplinapp.org/privacy" target="_blank" rel="noopener noreferrer" class="footer__link-item">Privacy Policy</a></li></ul></div></div><div class="footer__bottom text--center"><div class="footer__copyright">Copyright © 2016-2024 Laurent Cozic</div></div></div></footer></div>
<script src="/assets/js/runtime~main.1fb4f966.js"></script>
<script src="/assets/js/main.aa9faae4.js"></script>
</body>
</html>