You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
<htmllang="en"><head><metacharset="UTF-8"><title>Test timeouts in Gleam | Gears</title><linkhref="/style.css" rel="stylesheet"><linkhref="https://rsms.me/" rel="preconnect"><linkhref="https://rsms.me/inter/inter.css" rel="stylesheet"><linkhref="/favicon.svg" rel="icon" type="image/svg+xml"><linkhref="/favicon.ico" rel="alternate icon" sizes="48x48" type="image/png"><linkhref="/apple-touch-icon.png" rel="apple-touch-icon" sizes="192x192"></head><bodyclass="min-h-screen bg-slate-800 text-white"><headerclass="bg-purple-700 flex w-full select-none fixed"><navclass="flex h-16 grow items-center justify-between gap-4 px-4 text-white"><aclass="heading" href="/"><figureclass="flex flex-shrink-0 items-center space-x-1"><imgalt="Gears logo" class="w-16" height="64" src="/images/logo.svg" style="image-rendering:optimizeSpeed;image-rendering:pixelated;" width="64"><figcaptionclass="text-4xl font-bold font-celandine hidden md:block"><svgxmlns="http://www.w3.org/2000/svg"><pathxmlns="http://www.w3.org/2000/svg" class="animate-write" d="m 46.655648,87.273021 c 0.08105,4.602277 0.692125,6.832404 4.69733,4.361206 l 1.696146,2.728148 -14.225762,9.638735 c -2.121146,-1.55607 -3.838276,-4.0442 -4.678364,-7.342384 -3.390161,3.734254 -7.562386,6.271464 -13.082724,5.788494 C 10.581627,101.53029 2.8720353,90.133692 1.4418114,77.915968 0.26959238,64.592176 8.4519982,56.762609 16.647423,50.627146 c 6.709353,-4.814367 12.185664,-6.592535 16.425926,-6.221561 10.400636,0.909937 10.2848,16.055858 17.661218,12.831577 l 1.369105,2.78015 -13.921761,7.085583 C 29.896397,65.974923 28.524127,49.408937 19.629655,55.241389 c -4.548238,3.149245 -6.106269,8.978614 -4.24704,19.057204 1.461159,6.335369 5.770507,14.209799 12.214927,17.030887 2.403158,1.097035 4.205262,0.770993 6.046357,-0.922122 l 0.08399,-0.960053 0.300983,-3.440212 c -4.7513,-0.980005 -7.300468,-2.251058 -10.07761,0.0051 L 22.053124,83.749873 33.3637,74.259168 c 9.7606,0.853945 14.332923,4.801125 19.271184,0.879838 l 1.905129,2.18211 -7.907394,7.450543 c -0.0043,0.967047 0.07203,1.94111 0.02303,2.501151 z m 27.106123,0.967939 c 3.255101,3.879267 7.924879,5.594901 14.610274,2.013462 L 89.84759,92.997687 71.511182,104.62772 C 62.371276,103.58301 53.002118,82.748534 59.5709,73.029912 61.983775,69.728218 72.927415,59.493724 79.332135,60.054064 85.49365,60.593125 92.577447,70.199104 92.109323,75.549881 Z M 70.902742,68.629587 c -3.536763,2.141364 -1.750046,9.73174 1.253752,15.549655 L 79.558343,78.94493 C 78.612783,73.878931 74.248977,66.798328 70.902742,68.629587 Z m 62.806708,23.029124 1.74528,2.221251 -13.08952,10.709588 c -2.6179,0 -5.2358,-4.839141 -5.71178,-8.567661 l -11.7409,8.567661 c -6.505075,-0.0794 -10.709601,-7.61571 -9.916305,-13.24816 1.269292,-8.250355 9.123005,-13.010178 19.832605,-16.104062 -3.49054,-5.553124 -13.08951,-4.997811 -19.0393,-1.348612 l -1.586601,-2.459244 14.993441,-10.78893 c 9.28166,0 19.19795,1.665941 19.43593,14.438129 l 0.0794,12.375534 c -0.0794,4.125169 1.26928,6.901741 4.99782,4.204506 z m -22.60914,3.490534 4.99781,-3.252544 -0.0794,-12.930849 c -10.23362,3.728531 -10.70961,12.930849 -4.91847,16.183393 z m 51.19467,-16.075266 c -2.21157,-3.712255 -5.13397,-8.846224 -8.45131,-5.765843 l -0.47391,0.473911 v 1.184756 l 0.079,12.795432 c -0.079,4.028194 1.18475,6.555693 4.897,3.949214 l 1.81664,2.448509 -13.0324,10.504892 c -3.55428,-2.21157 -6.23973,-6.792636 -6.16074,-13.664255 V 78.679058 c -0.15797,-4.818028 -1.97461,-6.397712 -6.63468,-3.396316 L 132.99186,72.755248 147.13,60.907625 c 3.08039,2.290541 4.89704,4.423114 5.68687,7.740447 l 8.05639,-7.740447 c 6.00279,0 11.68966,9.636068 11.68966,9.636068 z m 19.14678,-9.156439 c 4.4536,7.601839 23.80372,5.375035 23.80372,20.962647 0,10.442913 -10.13577,13.207223 -19.5037,13.207223 -7.14112,0 -13.8983,-2.45716 -16.12512,-6.757188 l 11.36438,-10.596498 1.84287,1.45894 c -2.91787,2.841084 11.134,6.987545 15.05009,6.987545 0.46073,-6.296472 -26.33768,-10.058994 -26.33768,-19.580489 0,-8.369699 13.89831,-14.05188 13.89831,-14.05188 7.83221,0 16.2019,4.4536 21.11622,1.61251 l 1.22858,1.689298 -12.90008,10.289358 c -4.99112,0 -11.44115,-8.292917 -13.43759,-5.221466 z" style="fill:none;stroke:#ffffff;stroke-width:1px;stroke-dasharray:330;stroke-dashoffset:330;"></path></svg></figcaption></figure></a></nav></header><mainclass="py-24"><divclass="mx-auto max-w-3xl"><h1class="text-3xl font-bold leading-tight text-center">Test timeouts in Gleam</h1></div><divclass="mx-auto max-w-4xl py-8 leading-8"><h2class="text-xl font-bold text-center m-0">2025-11-25</h2><p>If you don't care about the backstory and just want to know the answer, you can
3
+
<aclass="underline" href="#How-do-I-configure-my-test-timeout" target>skip there</a>.</p><h2id="How-Gleam-tests-work">How Gleam tests work</h2><p>When you create a new Gleam project, there are two dependencies that are added
4
+
automatically by the build tool. These are <aclass="underline" href="https://hexdocs.pm/gleam_stdlib" target="_blank"><code>gleam_stdlib</code></a>,
5
+
the Gleam standard library, and <aclass="underline" href="https://hexdocs.pm/gleeunit" target="_blank"><code>gleeunit</code></a>, the
6
+
default test runner for Gleam.</p><p>Both of these dependencies are technically optional, but they are added by default
7
+
to make it easier to start a new project, since most projects use both the above
8
+
packages.</p><p>See, when you run <code>gleam test</code> in the terminal, while it may seem that the Gleam
9
+
build tool finds all your test functions magically, all it's really doing is calling
10
+
the <code>main</code> function of the module named <code>$PROJECT_test</code>, which by default calls
11
+
out to <code>gleeunit</code>, which is the code that's really in charge of running your tests.</p><h2id="What-is-gleeunit">What is gleeunit?</h2><p>On the Erlang target, the <code>gleeunit</code> library is a thin wrapper for
12
+
<aclass="underline" href="https://www.erlang.org/doc/apps/eunit/chapter.html" target="_blank"><code>EUnit</code></a>, which is a test
13
+
runner built into OTP. On JavaScript, <code>gleeunit</code> implements a custom test runner
14
+
that has similar (but not identical) features to <code>EUnit</code>.</p><p>Somewhat unfortunately, EUnit comes with a default timeout of 5 seconds, and
15
+
seemingly <aclass="underline" href="https://github.com/lpil/gleeunit/issues/51" target="_blank">no way to globally adjust it</a>
16
+
so if any test runs for longer than that it is immediately terminated.</p><p>EUnit has a somewhat unconventional API. As the default Gleam project explains,
17
+
it runs all public functions whose names end in <code>_test</code>. But there's a second
18
+
more obscure API, in the form of <strong>test generators</strong>.</p><p>Test generators are another kind of EUnit test. Test generator functions end
19
+
in <code>*_test_</code> (note the trailing underscore), and they have the ability to configure
20
+
various parts of how EUnit runs. It's detailed in the EUnit documentation,
21
+
but here we will just cover the most commonly used one, which is the timeout.</p><h2id="How-do-I-configure-my-test-timeout">How do I configure my test timeout?</h2><p>EUnit test generators allow returning extra values along with a function to call
22
+
in order to configure it. In Erlang syntax, here is how you would configure the
23
+
timeout for your test, to be 60 seconds instead of 5:</p><pre><codedata-lang="erlang"><span><spanclass=hl-function>something_test_</span><spanclass=hl-punctuation>(</span><spanclass=hl-punctuation>)</span><spanclass=hl-punctuation>-></span>
</span></code></pre><p>So, what does this translate to Gleam? Well, there are actually two ways to do it.
28
+
The first is to use the <code>atom.create</code> function from the <aclass="underline" href="https://hexdocs.pm/gleam_erlang" target="_blank"><code>gleam_erlang</code></a>
29
+
library. This creates basically the same as the Erlang code:</p><pre><codedata-lang="gleam"><span><spanclass=hl-keyword>import</span><spanclass=hl-module>gleam/erlang/atom</span>
... <spanclass=hl-comment>// The actual body of your test</span>
34
+
})
35
+
}
36
+
</span></code></pre><p>This works, but it has a couple of drawbacks. Firstly, you need to pull in a new
37
+
library just to create this one atom, and secondly it just doesn't look very nice.
38
+
My preferred solution takes advantage of the way that custom types are represented
39
+
in Gleam.</p><p>When Gleam compiles to Erlang, Gleam custom types become an Erlang tuple tagged
40
+
with an atom. So the Gleam value <code>Ok(10)</code> becomes the Erlang <code>{ok, 10}</code>. This is
41
+
perfect for what we need, because it's the exact same format as what EUnit expects.
42
+
Using that knowledge we can define a custom type to represent the timeout tuple:</p><pre><codedata-lang="gleam"><span><spanclass=hl-keyword>pub</span><spanclass=hl-keyword>type</span><spanclass=hl-variant>Timeout</span>(a) {
43
+
<spanclass=hl-variant>Timeout</span>(time: <spanclass=hl-variant>Int</span>, function: <spanclass=hl-keyword>fn</span>() -> a)
44
+
}
45
+
</span></code></pre><p>You can use <code>Float</code> instead for <code>time</code> here, but I find I rarely need to set my
46
+
timeout to a fraction of a second, so <code>Int</code> is more convenient. Now, we can take
47
+
advantage of Gleam's <aclass="underline" href="https://tour.gleam.run/advanced-features/use/" target="_blank"><code>use</code> syntax</a>,
48
+
which allows us to turn a call to a higher order function — where we pass an anonymous
49
+
function, like we did in the previous example — into a flattened statement.
50
+
We now get a much nicer looking test:</p><pre><codedata-lang="gleam"><span><spanclass=hl-keyword>pub</span><spanclass=hl-keyword>type</span><spanclass=hl-variant>Timeout</span>(a) {
51
+
<spanclass=hl-variant>Timeout</span>(time: <spanclass=hl-variant>Int</span>, function: <spanclass=hl-keyword>fn</span>() -> a)
... <spanclass=hl-comment>// The actual body of your test</span>
57
+
}
58
+
</span></code></pre><p>Great! We've successfully worked around EUnit's annoying timeout. Job done! But
59
+
wait...</p><h2id="Multi-target-tests">Multi-target tests</h2><p>Remember when I mentioned earlier about how <code>gleeunit</code> works differently on the
60
+
JavaScript target? Well, the good news is that it doesn't have a timeout like on
61
+
the Erlang target, but the bad news is that it doesn't support test generators.
62
+
So if all your tests are called <code>*_test_</code>, none of them are going to run on
63
+
the JavaScript target.</p><p>The only real way to get around this is to write a bit of extra boilerplate for
64
+
all of your tests. You need to write a test that runs only on JavaScript, that
65
+
calls the same code as the Erlang test. There's only really one way achieve this,
66
+
with the <code>@target</code> attribute, and it's not pretty. Here's an example:</p><pre><codedata-lang="gleam"><span><spanclass=hl-comment>// This runs on Erlang</span>
</span></code></pre><p>The <code>@target</code> attribute is deprecated, and you shouldn't use it really, but there
78
+
isn't any alternative for this specific case. Hopefully soon we will have an
79
+
alternative, both to <code>@target</code>, and to this problem of different behaviour in the
80
+
test runner across targets.</p><h2id="Conclusion">Conclusion</h2><p>If you want to change the timeout of a test that only runs on Erlang, it's not
81
+
very hard. If you want to have tests that run on both targets for longer than 5
82
+
seconds, it gets messy.
83
+
Hopefully there will be a better way to do it in the near future.</p></div></main><footerclass="right-5 bottom-4 fixed">Made with <aclass="underline" href="https://lustre.build" target="_blank">Lustre</a> and <aclass="underline" href="https://gleam.run" target="_blank">Gleam</a><br>Source: <aclass="underline" href="https://github.com/GearsDatapacks/GearsDatapacks.github.io" target="_blank">GitHub</a></footer></body></html>
<htmllang="en"><head><metacharset="UTF-8"><title>Blog | Gears</title><linkhref="/style.css" rel="stylesheet"><linkhref="https://rsms.me/" rel="preconnect"><linkhref="https://rsms.me/inter/inter.css" rel="stylesheet"><linkhref="/favicon.svg" rel="icon" type="image/svg+xml"><linkhref="/favicon.ico" rel="alternate icon" sizes="48x48" type="image/png"><linkhref="/apple-touch-icon.png" rel="apple-touch-icon" sizes="192x192"></head><bodyclass="min-h-screen bg-slate-800 text-white"><headerclass="bg-purple-700 flex w-full select-none fixed"><navclass="flex h-16 grow items-center justify-between gap-4 px-4 text-white"><aclass="heading" href="/"><figureclass="flex flex-shrink-0 items-center space-x-1"><imgalt="Gears logo" class="w-16" height="64" src="/images/logo.svg" style="image-rendering:optimizeSpeed;image-rendering:pixelated;" width="64"><figcaptionclass="text-4xl font-bold font-celandine hidden md:block"><svgxmlns="http://www.w3.org/2000/svg"><pathxmlns="http://www.w3.org/2000/svg" class="animate-write" d="m 46.655648,87.273021 c 0.08105,4.602277 0.692125,6.832404 4.69733,4.361206 l 1.696146,2.728148 -14.225762,9.638735 c -2.121146,-1.55607 -3.838276,-4.0442 -4.678364,-7.342384 -3.390161,3.734254 -7.562386,6.271464 -13.082724,5.788494 C 10.581627,101.53029 2.8720353,90.133692 1.4418114,77.915968 0.26959238,64.592176 8.4519982,56.762609 16.647423,50.627146 c 6.709353,-4.814367 12.185664,-6.592535 16.425926,-6.221561 10.400636,0.909937 10.2848,16.055858 17.661218,12.831577 l 1.369105,2.78015 -13.921761,7.085583 C 29.896397,65.974923 28.524127,49.408937 19.629655,55.241389 c -4.548238,3.149245 -6.106269,8.978614 -4.24704,19.057204 1.461159,6.335369 5.770507,14.209799 12.214927,17.030887 2.403158,1.097035 4.205262,0.770993 6.046357,-0.922122 l 0.08399,-0.960053 0.300983,-3.440212 c -4.7513,-0.980005 -7.300468,-2.251058 -10.07761,0.0051 L 22.053124,83.749873 33.3637,74.259168 c 9.7606,0.853945 14.332923,4.801125 19.271184,0.879838 l 1.905129,2.18211 -7.907394,7.450543 c -0.0043,0.967047 0.07203,1.94111 0.02303,2.501151 z m 27.106123,0.967939 c 3.255101,3.879267 7.924879,5.594901 14.610274,2.013462 L 89.84759,92.997687 71.511182,104.62772 C 62.371276,103.58301 53.002118,82.748534 59.5709,73.029912 61.983775,69.728218 72.927415,59.493724 79.332135,60.054064 85.49365,60.593125 92.577447,70.199104 92.109323,75.549881 Z M 70.902742,68.629587 c -3.536763,2.141364 -1.750046,9.73174 1.253752,15.549655 L 79.558343,78.94493 C 78.612783,73.878931 74.248977,66.798328 70.902742,68.629587 Z m 62.806708,23.029124 1.74528,2.221251 -13.08952,10.709588 c -2.6179,0 -5.2358,-4.839141 -5.71178,-8.567661 l -11.7409,8.567661 c -6.505075,-0.0794 -10.709601,-7.61571 -9.916305,-13.24816 1.269292,-8.250355 9.123005,-13.010178 19.832605,-16.104062 -3.49054,-5.553124 -13.08951,-4.997811 -19.0393,-1.348612 l -1.586601,-2.459244 14.993441,-10.78893 c 9.28166,0 19.19795,1.665941 19.43593,14.438129 l 0.0794,12.375534 c -0.0794,4.125169 1.26928,6.901741 4.99782,4.204506 z m -22.60914,3.490534 4.99781,-3.252544 -0.0794,-12.930849 c -10.23362,3.728531 -10.70961,12.930849 -4.91847,16.183393 z m 51.19467,-16.075266 c -2.21157,-3.712255 -5.13397,-8.846224 -8.45131,-5.765843 l -0.47391,0.473911 v 1.184756 l 0.079,12.795432 c -0.079,4.028194 1.18475,6.555693 4.897,3.949214 l 1.81664,2.448509 -13.0324,10.504892 c -3.55428,-2.21157 -6.23973,-6.792636 -6.16074,-13.664255 V 78.679058 c -0.15797,-4.818028 -1.97461,-6.397712 -6.63468,-3.396316 L 132.99186,72.755248 147.13,60.907625 c 3.08039,2.290541 4.89704,4.423114 5.68687,7.740447 l 8.05639,-7.740447 c 6.00279,0 11.68966,9.636068 11.68966,9.636068 z m 19.14678,-9.156439 c 4.4536,7.601839 23.80372,5.375035 23.80372,20.962647 0,10.442913 -10.13577,13.207223 -19.5037,13.207223 -7.14112,0 -13.8983,-2.45716 -16.12512,-6.757188 l 11.36438,-10.596498 1.84287,1.45894 c -2.91787,2.841084 11.134,6.987545 15.05009,6.987545 0.46073,-6.296472 -26.33768,-10.058994 -26.33768,-19.580489 0,-8.369699 13.89831,-14.05188 13.89831,-14.05188 7.83221,0 16.2019,4.4536 21.11622,1.61251 l 1.22858,1.689298 -12.90008,10.289358 c -4.99112,0 -11.44115,-8.292917 -13.43759,-5.221466 z" style="fill:none;stroke:#ffffff;stroke-width:1px;stroke-dasharray:330;stroke-dashoffset:330;"></path></svg></figcaption></figure></a></nav></header><mainclass="py-24"><divclass="mx-auto max-w-3xl"><h1class="text-3xl font-bold leading-tight text-center">My Blog</h1></div><divclass="mx-auto max-w-4xl py-8 leading-8"><div><aclass="underline" href="/blog/gleam-test-timeouts"><h2class="text-xl font-bold">Test timeouts in Gleam</h2></a><spanclass="text-sm">2025-11-25</span><pclass="text-lg">By default, Gleam tests come with a timeout of 5 seconds. It's not as easy as you might think to remove it.</p></div></div></main><footerclass="right-5 bottom-4 fixed">Made with <aclass="underline" href="https://lustre.build" target="_blank">Lustre</a> and <aclass="underline" href="https://gleam.run" target="_blank">Gleam</a><br>Source: <aclass="underline" href="https://github.com/GearsDatapacks/GearsDatapacks.github.io" target="_blank">GitHub</a></footer></body></html>
0 commit comments