<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title><![CDATA[Jake McCrary's articles on javascript]]></title>
  <link href="https://jakemccrary.com/atom.xml" rel="self"/>
  <link href="https://jakemccrary.com/"/>
  <updated>2026-03-14T17:06:03+00:00</updated>
  <id>https://jakemccrary.com/</id>
  <author>
    <name><![CDATA[Jake McCrary]]></name>
  </author>
  <entry>
    <id>https://jakemccrary.com/blog/2022/11/13/bookmarklets-on-mobile-are-useful/index.html</id>
    <link href="https://jakemccrary.com/blog/2022/11/13/bookmarklets-on-mobile-are-useful/index.html"/>
    <title><![CDATA[Bookmarklets on mobile are useful]]></title>
    <updated>2022-11-13T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p>Bookmarklets, little snippets of JavaScript that you keep around as a bookmark, are useful. They let you execute some JavaScript to perform almost any action you want on a website.</p><p>Some bookmarklets I use on my desktop browser include:</p><ol><li>A collection of bookmarklets that let you change the playback speed of most embedded videos.</li><li>A bookmarklet to manipulate the URL of the page you&apos;re visiting.</li><li>A <a href="https://pinboard.in/howto/">bookmarklet</a> to save the current page&apos;s URL to pinboard.in.</li></ol><p>For years, I thought I was restricted to only using bookmarklets in my desktop web browser. I hadn&apos;t effectively used mobile bookmarks before and thought that clicking them would be a huge pain.</p><p>It turns out, I was wrong! I recently learned that if you start typing a bookmark&apos;s title into your mobile browser&apos;s location bar, it will let you select the bookmark. This means you can easily execute a bookmarklet just by starting to type its name and clicking it when it appears. This &quot;search for bookmark in location bar&quot; technique works with at least Google Chrome and Brave running in Android.</p><p>Below are the two bookmarklets I use regularly on my phone. They exist to bypass paywalls.</p><p>This one prepends <code>http://archive.is/</code> to the current URL:</p><pre><code class="language-javascript">javascript:(function() {window.location=&quot;http://archive.is/&quot;+window.location.toString();}())
</code></pre><p>This one changes <code>theatlantic.com</code> to <code>theatlantic.com.</code> (though it no longer gets around their paywall):</p><pre><code class="language-javascript">javascript:(function() {window.location=window.location.href.replace(/theatlantic.com/, &apos;theatlantic.com.&apos;);}())
</code></pre><p>To get them onto my phone, I added them a bookmarks on my laptop&apos;s Chrome and synced them to my mobile phone. Once in my mobile Chrome, I edited the bookmark in mobile Chrome, copied the code, and pasted it into a bookmark in Brave.</p><p>I type three characters into my mobile browser&apos;s location bar before I can select either of these bookmarklets. That is quicker than editing the URLs by hand and has improved the experience of reading articles on my phone.</p></div>]]></content>
  </entry>
  <entry>
    <id>https://jakemccrary.com/blog/2019/02/13/testing-asynchronous-javascript-with-jasmine/index.html</id>
    <link href="https://jakemccrary.com/blog/2019/02/13/testing-asynchronous-javascript-with-jasmine/index.html"/>
    <title><![CDATA[Testing asynchronous JavaScript with Jasmine]]></title>
    <updated>2019-02-13T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p>I was recently adding a feature to an internal web UI that caught all unhandled JavaScript errors and reported them to the backend service. The implementation went smoothly with most of the effort spent figuring out how to test the code that was reporting the errors.</p><p>If the error reporting failed, I didn&apos;t want to trigger reporting another error or completely lose that error. I decided to log a reporting error to the console. I wanted to write a test showing that errors reporting errors were handled so that a future me, or another developer, didn&apos;t accidentally remove this special error handling and enable a never ending cycle of of reporting failed reporting attempts.</p><p>It took me a while to figure out how to do this. I searched the web and found various articles about using <a href="https://jasmine.github.io/">Jasmine</a> to do async tests. They were helpful but I also wanted to mock out a function, <code>console.error</code>, and assert that it was called. None of the examples I found were explicit about doing something like this. I forget how many different approaches I tried, but it took a while to figure out the below solution.</p><p>Here is the code I wanted to test.</p><pre><code class="language-javascript">function reportEvent(event) {
  return fetch(&apos;/report-event&apos;, {
    method: &apos;POST&apos;,
    headers: {&apos;Content-Type&apos;: &apos;application/json&apos;},
    body: JSON.stringify({name: &apos;ui name&apos;, ...event})
  }).catch(function(e) { console.error(&apos;Problem reporting event:&apos;, e)});
}
</code></pre><p>It takes an incoming <code>event</code> object and merges it with a default value and posts that to the backing service. <code>fetch</code> returns a Promise and the code handles errors by calling <code>catch</code> on it and logging.</p><p>Below is what I eventually came up with for testing the error handling feature of <code>reportEvent</code>.</p><pre><code class="language-javascript">describe(&apos;reporting events&apos;, function() {
  it(&apos;logs errors&apos;, (done) =&gt; {
    spyOn(console, &apos;error&apos;).and.callFake(() =&gt; {
      expect(console.error).toHaveBeenCalled();
      done();
    });
    spyOn(window, &apos;fetch&apos;).and.returnValue(Promise.reject(&apos;error!&apos;));
    reportEvent({level: &apos;WARN&apos;, msg: &apos;ERROR!&apos;});
  });
});
</code></pre><p>This uses <code>spyOn</code> to mock out <code>fetch</code> and <code>console.error</code>. The <code>fetch</code> call is told to return a rejected Promise. The <code>console.error</code> spy is a bit more interesting.</p><p>The <code>console.error</code> spy is told to call a fake function. That function asserts that the <code>console.error</code> spy has been called. More importantly, it also calls a <code>done</code> function. That <code>done</code> function is a callback passed to your test by Jasmine. Calling <code>done</code> signals that your async work is completed.</p><p>If <code>done</code> is never called then Jasmine will fail the test after some amount of time. By calling <code>done</code> in our <code>console.error</code> fake, we&apos;re able to signal to Jasmine that we&apos;ve handled the rejected promise.</p><p>You don&apos;t actually need the <code>expect(console.error).toHaveBeenCalled();</code> as <code>done</code> won&apos;t be called unless <code>console.error</code> has been called. If you don&apos;t have it though then Jasmine will complain there are no assertions in the test.</p><p>So there we have it, an example of using some of Jasmine&apos;s asynchronous test features with spies. I wish I had found an article like this when I started this task. Hopefully it saves you, and future me, some time.</p></div>]]></content>
  </entry>
  <entry>
    <id>https://jakemccrary.com/blog/2016/04/08/book-review-serverless-single-page-apps/index.html</id>
    <link href="https://jakemccrary.com/blog/2016/04/08/book-review-serverless-single-page-apps/index.html"/>
    <title><![CDATA[Book review: Serverless Single Page Apps]]></title>
    <updated>2016-04-08T23:59:59+00:00</updated>
    <content type="html"><![CDATA[<div><p>I&apos;ve read Ben Rady&apos;s <a href="https://pragprog.com/book/brapps/serverless-single-page-apps">Serverless Single Page Apps</a> twice now. As an early technical reviewer, I was able to watch and take part in the book&apos;s evolution. The early draft was good but the most recent near-final draft was better.</p><p><em>Serverless Single Page Apps</em> walks you through building a low-cost, highly-available, serverless single page web application. It does this on top of various Amazon web services (DynamoDB, Cognito, Lambda, API Gateway, S3). If you follow along you&apos;ll end up with a simple web application with authentication.</p><p>The book is very enjoyable. The examples are clear and the book is well written. The book uses JavaScript to implement the serverless application. For the user interface it uses plain JavaScript with a bit of jQuery and for the AWS Lambda functions you dip into some Node.js. <em>Serverless</em> doesn&apos;t distract you from learning about serverless applications by forcing you to learn new JavaScript frameworks or libraries.</p><p>One of my favorite parts of the book is Ben&apos;s use of test driven development. The examples provided give the reader a decent taste of the benefits of test-first development. Having the tests helped me when I made some silly mistakes in later parts of the book.</p><p>Overall I&apos;d recommend this book to developers who are interested in learning what a serverless application might look like. If you follow along you&apos;ll know how to build one by the end and will have a good starting point for diving deeper into the topic.</p></div>]]></content>
  </entry>
</feed>
