Skip to content

Commit fd974ec

Browse files
deploy: b2f2d8d
1 parent e0d6980 commit fd974ec

File tree

3 files changed

+63
-10
lines changed

3 files changed

+63
-10
lines changed

blog/gleam-test-timeouts/index.html

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,50 +21,83 @@
2121
various parts of how EUnit runs. It's detailed in the EUnit documentation,
2222
but here we will just cover the most commonly used one, which is the timeout.</p><h2 id="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
2323
in order to configure it. In Erlang syntax, here is how you would configure the
24-
timeout for your test, to be 60 seconds instead of 5:</p><pre><code data-lang="erlang"><span><span class=hl-function>something_test_</span><span class=hl-punctuation>(</span><span class=hl-punctuation>)</span> <span class=hl-punctuation>-&gt;</span>
24+
timeout for your test, to be 60 seconds instead of 5:</p><div class="codeblock"><button class="copy-button" onclick="navigator.clipboard.writeText(`something_test_() -&gt;
25+
{timeout, 60, fun () -&gt;
26+
... % The actual body of your test
27+
}.
28+
`)">copy</button><pre><code data-lang="erlang"><span><span class=hl-function>something_test_</span><span class=hl-punctuation>(</span><span class=hl-punctuation>)</span> <span class=hl-punctuation>-&gt;</span>
2529
<span class=hl-punctuation>{</span><span class=hl-atom>timeout</span><span class=hl-punctuation>,</span> <span class=hl-number>60</span><span class=hl-punctuation>,</span> <span class=hl-keyword>fun</span> <span class=hl-punctuation>(</span><span class=hl-punctuation>)</span> <span class=hl-punctuation>-&gt;</span>
2630
<span class=hl-punctuation>...</span> <span class=hl-comment>% The actual body of your test
2731
</span> <span class=hl-punctuation>}</span><span class=hl-punctuation>.</span>
28-
</span></code></pre><p>So, what does this translate to Gleam? Well, there are actually two ways to do it.
32+
</span></code></pre></div><p>So, what does this translate to Gleam? Well, there are actually two ways to do it.
2933
The first is to use the <code>atom.create</code> function from the <a class="underline" href="https://hexdocs.pm/gleam_erlang" target="_blank"><code>gleam_erlang</code></a>
30-
library. This creates basically the same as the Erlang code:</p><pre><code data-lang="gleam"><span><span class=hl-keyword>import</span> <span class=hl-module>gleam/erlang/atom</span>
34+
library. This creates basically the same as the Erlang code:</p><div class="codeblock"><button class="copy-button" onclick="navigator.clipboard.writeText(`import gleam/erlang/atom
35+
36+
pub fn something_test_() {
37+
#(atom.create(&quot;timeout&quot;), 60, fn() {
38+
... // The actual body of your test
39+
})
40+
}
41+
`)">copy</button><pre><code data-lang="gleam"><span><span class=hl-keyword>import</span> <span class=hl-module>gleam/erlang/atom</span>
3142

3243
<span class=hl-keyword>pub</span> <span class=hl-keyword>fn</span> <span class=hl-function>something_test_</span>() {
3344
#(<span class=hl-module>atom</span>.<span class=hl-function>create</span>(<span class=hl-string>&quot;timeout&quot;</span>), <span class=hl-number>60</span>, <span class=hl-keyword>fn</span>() {
3445
... <span class=hl-comment>// The actual body of your test</span>
3546
})
3647
}
37-
</span></code></pre><p>This works, but it has a couple of drawbacks. Firstly, you need to pull in a new
48+
</span></code></pre></div><p>This works, but it has a couple of drawbacks. Firstly, you need to pull in a new
3849
library just to create this one atom, and secondly it just doesn&#39;t look very nice.
3950
My preferred solution takes advantage of the way that custom types are represented
4051
in Gleam.</p><p>When Gleam compiles to Erlang, Gleam custom types become an Erlang tuple tagged
4152
with an atom. So the Gleam value <code>Ok(10)</code> becomes the Erlang <code>{ok, 10}</code>. This is
4253
perfect for what we need, because it&#39;s the exact same format as what EUnit expects.
43-
Using that knowledge we can define a custom type to represent the timeout tuple:</p><pre><code data-lang="gleam"><span><span class=hl-keyword>pub</span> <span class=hl-keyword>type</span> <span class=hl-variant>Timeout</span>(a) {
54+
Using that knowledge we can define a custom type to represent the timeout tuple:</p><div class="codeblock"><button class="copy-button" onclick="navigator.clipboard.writeText(`pub type Timeout(a) {
55+
Timeout(time: Int, function: fn() -&gt; a)
56+
}
57+
`)">copy</button><pre><code data-lang="gleam"><span><span class=hl-keyword>pub</span> <span class=hl-keyword>type</span> <span class=hl-variant>Timeout</span>(a) {
4458
<span class=hl-variant>Timeout</span>(time: <span class=hl-variant>Int</span>, function: <span class=hl-keyword>fn</span>() -&gt; a)
4559
}
46-
</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
60+
</span></code></pre></div><p>You can use <code>Float</code> instead for <code>time</code> here, but I find I rarely need to set my
4761
timeout to a fraction of a second, so <code>Int</code> is more convenient. Now, we can take
4862
advantage of Gleam&#39;s <a class="underline" href="https://tour.gleam.run/advanced-features/use/" target="_blank"><code>use</code> syntax</a>,
4963
which allows us to turn a call to a higher order function — where we pass an anonymous
5064
function, like we did in the previous example — into a flattened statement.
51-
We now get a much nicer looking test:</p><pre><code data-lang="gleam"><span><span class=hl-keyword>pub</span> <span class=hl-keyword>type</span> <span class=hl-variant>Timeout</span>(a) {
65+
We now get a much nicer looking test:</p><div class="codeblock"><button class="copy-button" onclick="navigator.clipboard.writeText(`pub type Timeout(a) {
66+
Timeout(time: Int, function: fn() -&gt; a)
67+
}
68+
69+
pub fn something_test_() {
70+
use &lt;- Timeout(60)
71+
... // The actual body of your test
72+
}
73+
`)">copy</button><pre><code data-lang="gleam"><span><span class=hl-keyword>pub</span> <span class=hl-keyword>type</span> <span class=hl-variant>Timeout</span>(a) {
5274
<span class=hl-variant>Timeout</span>(time: <span class=hl-variant>Int</span>, function: <span class=hl-keyword>fn</span>() -&gt; a)
5375
}
5476

5577
<span class=hl-keyword>pub</span> <span class=hl-keyword>fn</span> <span class=hl-function>something_test_</span>() {
5678
<span class=hl-keyword>use</span> &lt;- <span class=hl-variant>Timeout</span>(<span class=hl-number>60</span>)
5779
... <span class=hl-comment>// The actual body of your test</span>
5880
}
59-
</span></code></pre><p>Great! We&#39;ve successfully worked around EUnit&#39;s annoying timeout. Job done! But
81+
</span></code></pre></div><p>Great! We&#39;ve successfully worked around EUnit&#39;s annoying timeout. Job done! But
6082
wait...</p><h2 id="Multi-target-tests">Multi-target tests</h2><p>Remember when I mentioned earlier about how <code>gleeunit</code> works differently on the
6183
JavaScript target? Well, the good news is that it doesn&#39;t have a timeout like on
6284
the Erlang target, but the bad news is that it doesn&#39;t support test generators.
6385
So if all your tests are called <code>*_test_</code>, none of them are going to run on
6486
the JavaScript target.</p><p>The only real way to get around this is to write a bit of extra boilerplate for
6587
all of your tests. You need to write a test that runs only on JavaScript, that
6688
calls the same code as the Erlang test. There&#39;s only really one way achieve this,
67-
with the <code>@target</code> attribute, and it&#39;s not pretty. Here&#39;s an example:</p><pre><code data-lang="gleam"><span><span class=hl-comment>// This runs on Erlang</span>
89+
with the <code>@target</code> attribute, and it&#39;s not pretty. Here&#39;s an example:</p><div class="codeblock"><button class="copy-button" onclick="navigator.clipboard.writeText(`// This runs on Erlang
90+
pub fn something_test_() {
91+
use &lt;- Timeout(60)
92+
... // The actual body of your test
93+
}
94+
95+
// This runs on JavaScript
96+
@target(javascript)
97+
pub fn something_test() {
98+
something_test_().function()
99+
}
100+
`)">copy</button><pre><code data-lang="gleam"><span><span class=hl-comment>// This runs on Erlang</span>
68101
<span class=hl-keyword>pub</span> <span class=hl-keyword>fn</span> <span class=hl-function>something_test_</span>() {
69102
<span class=hl-keyword>use</span> &lt;- <span class=hl-variant>Timeout</span>(<span class=hl-number>60</span>)
70103
... <span class=hl-comment>// The actual body of your test</span>
@@ -75,7 +108,7 @@
75108
<span class=hl-keyword>pub</span> <span class=hl-keyword>fn</span> <span class=hl-function>something_test</span>() {
76109
<span class=hl-function>something_test_</span>().<span class=hl-function>function</span>()
77110
}
78-
</span></code></pre><p>The <code>@target</code> attribute is deprecated, and you shouldn&#39;t use it really, but there
111+
</span></code></pre></div><p>The <code>@target</code> attribute is deprecated, and you shouldn&#39;t use it really, but there
79112
isn&#39;t any alternative for this specific case. Hopefully soon we will have an
80113
alternative, both to <code>@target</code>, and to this problem of different behaviour in the
81114
test runner across targets.</p><h2 id="Conclusion">Conclusion</h2><p>If you want to change the timeout of a test that only runs on Erlang, it&#39;s not

main.css

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,4 +63,14 @@ pre code .hl-atom {
6363

6464
pre code .hl-variant {
6565
color: #ffddfa
66+
}
67+
68+
button.copy-button {
69+
position: absolute;
70+
top: 0.1rem;
71+
right: 0.5rem;
72+
}
73+
74+
div.codeblock {
75+
position: sticky;
6676
}

style.css

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -835,6 +835,16 @@ pre code .hl-variant {
835835
color: #ffddfa
836836
}
837837

838+
button.copy-button {
839+
position: absolute;
840+
top: 0.1rem;
841+
right: 0.5rem;
842+
}
843+
844+
div.codeblock {
845+
position: sticky;
846+
}
847+
838848
.hover\:underline:hover {
839849
text-decoration-line: underline;
840850
}

0 commit comments

Comments
 (0)