Skip to content

Commit

Permalink
Add typing-jest-spies.md
Browse files Browse the repository at this point in the history
  • Loading branch information
smack0007 committed Oct 24, 2023
1 parent a5f3b01 commit 7834361
Show file tree
Hide file tree
Showing 26 changed files with 629 additions and 457 deletions.
35 changes: 35 additions & 0 deletions blog/2023/typing-jest-spies.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0"><meta name="description" content=""><meta name="author" content="Zachary Snow"><title>Typing jest Spies</title><base href="https://smack0007.github.io"></base><link rel="stylesheet" type="text/css" href="css/style.css"><link rel="alternate" type="application/rss+xml" title="The Blog of Zachary Snow" href="feed.rss"><link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png"><link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png"><link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png"><link rel="manifest" href="/site.webmanifest"></head><body><div class="wrap"><nav class="navbar navbar-expand-lg navbar-dark bg-dark"><h1><a class="navbar-brand" href="/">The Blog of Zachary Snow</a></h1><button id="navbar-toggler" class="navbar-toggler" type="button" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation"><span class="navbar-toggler-icon"></span></button><div class="collapse navbar-collapse" id="navbarSupportedContent"><ul class="navbar-nav mr-auto"><li class="nav-item"><a class="nav-link active" href="index.html">Home<span class="visually-hidden">(current)</span></a></li><li class="nav-item"><a class="nav-link" href="about.html">About</a></li><li class="nav-item"><a class="nav-link" href="tags/index.html">Tags</a></li></ul><div class="social my-2 my-lg-0"><a href="https://twitter.com/smack0007" class="twitter" title="Twitter"><span class="icon-twitter"></span></a><a href="https://github.com/smack0007" class="github" title="Github"><span class="icon-github"></span></a><a href="https://paypal.me/smack0007" class="coffee" title="Buy me a Coffee"><span class="icon-mug"></span></a><a href="feed.rss" class="rss" title="RSS"><span class="icon-rss"></span></a></div></div></nav><main class="container"><div class="posts"><div class="post"><div class="post-header"><h2><a href="blog/2023/typing-jest-spies.html">Typing jest Spies</a></h2><div class="meta"><span class="date"><span class="icon-calendar"></span>October 24, 2023</span><span class="tags"><a href="tags/typescript/index.html"><span class="icon icon-price-tags"></span><span class="tagName">typescript</span></a><a href="tags/jest/index.html"><span class="icon icon-price-tags"></span><span class="tagName">jest</span></a></span></div></div><div class="content"><p>It often feels like <a href="https://www.typescriptlang.org/">TypeScript</a> was an afterthought in <a href="https://jestjs.io/">jest</a>.
Any time I need to type a variable that holds some data structure from jest it feels
like I need to dust off my old book of spells in order to find the correct incantation
to make <a href="https://eslint.org/">eslint</a> happy. A situation I finally figured
out a solution for is when you want to store the result of a call to <code>jest.spyOn</code> in a
shared variable:</p>
<pre><code class="hljs ts"><span class="hljs-keyword">let</span> <span class="hljs-attr">setTimeoutSpy</span>: jest.<span class="hljs-property">SpyInstance</span>;

<span class="hljs-title function_">beforeEach</span>(<span class="hljs-function">() =&gt;</span> {
setTimeoutSpy = jest.<span class="hljs-title function_">spyOn</span>(globalThis, <span class="hljs-string">&#x27;setTimeout&#x27;</span>).<span class="hljs-title function_">mockImplementation</span>(<span class="hljs-function">(<span class="hljs-params">callback</span>) =&gt;</span> {
<span class="hljs-title function_">callback</span>();
<span class="hljs-keyword">return</span> <span class="hljs-number">0</span> <span class="hljs-keyword">as</span> <span class="hljs-built_in">unknown</span> <span class="hljs-keyword">as</span> <span class="hljs-title class_">ReturnType</span>&lt;<span class="hljs-keyword">typeof</span> <span class="hljs-built_in">setTimeout</span>&gt;;
});
});

<span class="hljs-title function_">afterEach</span>(<span class="hljs-function">() =&gt;</span> {
setTimeoutSpy.<span class="hljs-title function_">mockRestore</span>();
});
</code></pre>
<p>Even though <code>jest.SpyInstance</code> is specified here as the type for <code>randomSpy</code> the information about exactly what
function is being spied on gets lost here. That means if elsewhere in the code if you try the following:</p>
<pre><code class="hljs ts"><span class="hljs-keyword">let</span> <span class="hljs-title function_">setTimeoutCallback</span> = (<span class="hljs-params"></span>) =&gt; {};
<span class="hljs-keyword">let</span> <span class="hljs-attr">setTimeoutDelay</span>: <span class="hljs-built_in">number</span> | <span class="hljs-literal">undefined</span> = <span class="hljs-literal">undefined</span>;
setTimeoutSpy.<span class="hljs-title function_">mockImplementation</span>(<span class="hljs-function">(<span class="hljs-params">callback, delay</span>) =&gt;</span> {
setTimeoutCallback = callback;
setTimeoutDelay = delay;
<span class="hljs-keyword">return</span> <span class="hljs-number">0</span> <span class="hljs-keyword">as</span> <span class="hljs-built_in">unknown</span> <span class="hljs-keyword">as</span> <span class="hljs-title class_">ReturnType</span>&lt;<span class="hljs-keyword">typeof</span> <span class="hljs-built_in">setTimeout</span>&gt;;
});
</code></pre>
<p><code>eslint</code> will complain that <code>callback</code> and <code>delay</code> have the type <code>any</code>. This is again due to the lost type information.
This problem can be resolved by using some TypeScript utility types when the spy variable is declared:</p>
<pre><code class="hljs ts"><span class="hljs-keyword">let</span> <span class="hljs-attr">setTimeoutSpy</span>: jest.<span class="hljs-property">SpyInstance</span>&lt;<span class="hljs-title class_">ReturnType</span>&lt;<span class="hljs-keyword">typeof</span> <span class="hljs-built_in">setTimeout</span>&gt;, <span class="hljs-title class_">Parameters</span>&lt;<span class="hljs-keyword">typeof</span> <span class="hljs-built_in">setTimeout</span>&gt;&gt;;
</code></pre>
<p>We use the built in <code>ReturnType</code> and <code>Parameters</code> utility types to perform the voodoo needed in order to make <code>eslint</code> happy.</p>
</div></div></div><div class="clear"></div></main><footer class="p-13 p-md-5 mt-5 text-center text-muted bg-light"><div class="container"><ul class="links"><li><a href="https://twitter.com/smack0007" class="twitter" title="Twitter">Twitter</a></li><li><a href="https://github.com/smack0007" class="github" title="Github">GitHub</a></li><li><a href="https://paypal.me/smack0007" class="coffee" title="Buy me a Coffee">Buy me a Coffee</a></li><li><a href="feed.rss" class="rss" title="RSS">RSS</a></li></ul><p class="mb-0">The Blog of Zachary Snow</p></div></footer></div><script type="text/javascript">document.getElementById('navbar-toggler').onclick = function(){ document.getElementById('navbarSupportedContent').classList.toggle('collapse'); };</script></body></html>
10 changes: 2 additions & 8 deletions blog/page10.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0"><meta name="description" content=""><meta name="author" content="Zachary Snow"><title>The Blog of Zachary Snow</title><base href="https://smack0007.github.io"></base><link rel="stylesheet" type="text/css" href="css/style.css"><link rel="alternate" type="application/rss+xml" title="The Blog of Zachary Snow" href="feed.rss"><link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png"><link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png"><link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png"><link rel="manifest" href="/site.webmanifest"></head><body><div class="wrap"><nav class="navbar navbar-expand-lg navbar-dark bg-dark"><h1><a class="navbar-brand" href="/">The Blog of Zachary Snow</a></h1><button id="navbar-toggler" class="navbar-toggler" type="button" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation"><span class="navbar-toggler-icon"></span></button><div class="collapse navbar-collapse" id="navbarSupportedContent"><ul class="navbar-nav mr-auto"><li class="nav-item"><a class="nav-link active" href="index.html">Home<span class="visually-hidden">(current)</span></a></li><li class="nav-item"><a class="nav-link" href="about.html">About</a></li><li class="nav-item"><a class="nav-link" href="tags/index.html">Tags</a></li></ul><div class="social my-2 my-lg-0"><a href="https://twitter.com/smack0007" class="twitter" title="Twitter"><span class="icon-twitter"></span></a><a href="https://github.com/smack0007" class="github" title="Github"><span class="icon-github"></span></a><a href="https://paypal.me/smack0007" class="coffee" title="Buy me a Coffee"><span class="icon-mug"></span></a><a href="feed.rss" class="rss" title="RSS"><span class="icon-rss"></span></a></div></div></nav><main class="container"><div class="posts"><div class="post"><div class="post-header"><h2><a href="blog/2014/code-from-when-i-was-young-and-stupid.html">Code from when I was young and stupid and needed the money</a></h2><div class="meta"><span class="date"><span class="icon-calendar"></span>June 18, 2014</span><span class="tags"><a href="tags/old-code/index.html"><span class="icon icon-price-tags"></span><span class="tagName">old-code</span></a><a href="tags/cpp/index.html"><span class="icon icon-price-tags"></span><span class="tagName">c++</span></a></span></div></div><div class="content"><p>We have had 2 interns at work for the past few weeks and one of the tasks we gave them was to implement <a href="http://en.wikipedia.org/wiki/Quick_sort">Quicksort</a>.
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0"><meta name="description" content=""><meta name="author" content="Zachary Snow"><title>The Blog of Zachary Snow</title><base href="https://smack0007.github.io"></base><link rel="stylesheet" type="text/css" href="css/style.css"><link rel="alternate" type="application/rss+xml" title="The Blog of Zachary Snow" href="feed.rss"><link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png"><link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png"><link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png"><link rel="manifest" href="/site.webmanifest"></head><body><div class="wrap"><nav class="navbar navbar-expand-lg navbar-dark bg-dark"><h1><a class="navbar-brand" href="/">The Blog of Zachary Snow</a></h1><button id="navbar-toggler" class="navbar-toggler" type="button" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation"><span class="navbar-toggler-icon"></span></button><div class="collapse navbar-collapse" id="navbarSupportedContent"><ul class="navbar-nav mr-auto"><li class="nav-item"><a class="nav-link active" href="index.html">Home<span class="visually-hidden">(current)</span></a></li><li class="nav-item"><a class="nav-link" href="about.html">About</a></li><li class="nav-item"><a class="nav-link" href="tags/index.html">Tags</a></li></ul><div class="social my-2 my-lg-0"><a href="https://twitter.com/smack0007" class="twitter" title="Twitter"><span class="icon-twitter"></span></a><a href="https://github.com/smack0007" class="github" title="Github"><span class="icon-github"></span></a><a href="https://paypal.me/smack0007" class="coffee" title="Buy me a Coffee"><span class="icon-mug"></span></a><a href="feed.rss" class="rss" title="RSS"><span class="icon-rss"></span></a></div></div></nav><main class="container"><div class="posts"><div class="post"><div class="post-header"><h2><a href="blog/2014/my-experience-with-opengl-vs-direct3d.html">My Experience with OpenGL vs Direct3D</a></h2><div class="meta"><span class="date"><span class="icon-calendar"></span>November 18, 2014</span><span class="tags"><a href="tags/graphics/index.html"><span class="icon icon-price-tags"></span><span class="tagName">graphics</span></a><a href="tags/opengl/index.html"><span class="icon icon-price-tags"></span><span class="tagName">opengl</span></a><a href="tags/direct3d/index.html"><span class="icon icon-price-tags"></span><span class="tagName">direct3D</span></a></span></div></div><div class="content"><p>I&#39;ve struggled a lot with myself over whether I should use OpenGL or Direct3D. There is no blanket answer to this question that anyone can tell you.
Both APIs have a very different feel and which one you prefer can only be decided on your own.</p><a class="readMore" href="blog/2014/my-experience-with-opengl-vs-direct3d.html">Read More</a></div></div><div class="post"><div class="post-header"><h2><a href="blog/2014/code-from-when-i-was-young-and-stupid.html">Code from when I was young and stupid and needed the money</a></h2><div class="meta"><span class="date"><span class="icon-calendar"></span>June 18, 2014</span><span class="tags"><a href="tags/old-code/index.html"><span class="icon icon-price-tags"></span><span class="tagName">old-code</span></a><a href="tags/cpp/index.html"><span class="icon icon-price-tags"></span><span class="tagName">c++</span></a></span></div></div><div class="content"><p>We have had 2 interns at work for the past few weeks and one of the tasks we gave them was to implement <a href="http://en.wikipedia.org/wiki/Quick_sort">Quicksort</a>.
This got me to thinking about my youth and some of the code I wrote back then. I&#39;ve decided to post it.</p><a class="readMore" href="blog/2014/code-from-when-i-was-young-and-stupid.html">Read More</a></div></div><div class="post"><div class="post-header"><h2><a href="blog/2014/adding-assembly-references-in-roslyn.html">Adding assembly references in Roslyn</a></h2><div class="meta"><span class="date"><span class="icon-calendar"></span>April 15, 2014</span><span class="tags"><a href="tags/net/index.html"><span class="icon icon-price-tags"></span><span class="tagName">.net</span></a><a href="tags/csharp/index.html"><span class="icon icon-price-tags"></span><span class="tagName">c#</span></a><a href="tags/roslyn/index.html"><span class="icon icon-price-tags"></span><span class="tagName">roslyn</span></a></span></div></div><div class="content"><p>In the Roslyn preview that was released at Build 2014 the way references to global assmeblies are added was changed. Before the preview I could use code like this:</p>
<pre><code class="hljs csharp"><span class="hljs-keyword">var</span> compilation = Compilation.Create(assemblyName, <span class="hljs-keyword">new</span> CompilationOptions(OutputKind.DynamicallyLinkedLibrary))
.AddReferences(MetadataReference.CreateAssemblyReference(<span class="hljs-string">&quot;mscorlib&quot;</span>))
Expand Down Expand Up @@ -29,11 +30,4 @@

<p>In After.cs, you can see that Component Glue is able to build the entire object graph for us. This will include all future dependencies as well so long as interfaces don&#39;t come into play. Should an interface be needed, you can just bind that single component.</p>
<p>This is a very powerful thing. If one component needs to take on a dependency, just ask for it in the constructor and Component Glue will handle it for you.</p>
</div></div><div class="post"><div class="post-header"><h2><a href="blog/2013/component-glue-v1-0.html">Component Glue v1.0</a></h2><div class="meta"><span class="date"><span class="icon-calendar"></span>June 11, 2013</span><span class="tags"><a href="tags/net/index.html"><span class="icon icon-price-tags"></span><span class="tagName">.net</span></a><a href="tags/csharp/index.html"><span class="icon icon-price-tags"></span><span class="tagName">c#</span></a><a href="tags/component-glue/index.html"><span class="icon icon-price-tags"></span><span class="tagName">component-glue</span></a><a href="tags/dependency-injection/index.html"><span class="icon icon-price-tags"></span><span class="tagName">dependency-injection</span></a><a href="tags/github/index.html"><span class="icon icon-price-tags"></span><span class="tagName">github</span></a><a href="tags/ioc/index.html"><span class="icon icon-price-tags"></span><span class="tagName">ioc</span></a><a href="tags/nuget/index.html"><span class="icon icon-price-tags"></span><span class="tagName">nuget</span></a></span></div></div><div class="content"><p>I finally brought Component Glue up to a state where I felt like the product was finished. You can get it via NuGet:</p>
<div class="nuget-badge">
`PM&gt; Install-Package ComponentGlue`
</div>

<p>or you can get the source from <a href="https://github.com/smack0007/ComponentGlue">GitHub</a>. The documentation is definitely sparse I know but I recommend taking a look at the unit tests to get a feel for what you can do with Component Glue.</p>
<p>Credit for the NuGet CSS <a href="http://www.arunrana.net/2012/01/design-of-nuget-package-installation.html">here</a>.</p>
</div></div></div><div class="clear"></div><nav aria-label="Page navigation"><ul class="pagination justify-content-center"><li class="page-item"><a href="blog/page11.html" class="page-link older">Older</a></li><li class="page-item"><a href="blog/page9.html" class="page-link newer">Newer</a></li></ul></nav></main><footer class="p-13 p-md-5 mt-5 text-center text-muted bg-light"><div class="container"><ul class="links"><li><a href="https://twitter.com/smack0007" class="twitter" title="Twitter">Twitter</a></li><li><a href="https://github.com/smack0007" class="github" title="Github">GitHub</a></li><li><a href="https://paypal.me/smack0007" class="coffee" title="Buy me a Coffee">Buy me a Coffee</a></li><li><a href="feed.rss" class="rss" title="RSS">RSS</a></li></ul><p class="mb-0">The Blog of Zachary Snow</p></div></footer></div><script type="text/javascript">document.getElementById('navbar-toggler').onclick = function(){ document.getElementById('navbarSupportedContent').classList.toggle('collapse'); };</script></body></html>
Loading

0 comments on commit 7834361

Please sign in to comment.