<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Cassey Lottman</title>
    <description>The latest articles on Forem by Cassey Lottman (@casseylottman).</description>
    <link>https://forem.com/casseylottman</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F143495%2Fb11b81c0-9a01-4673-ac3e-0e9872b832f5.jpg</url>
      <title>Forem: Cassey Lottman</title>
      <link>https://forem.com/casseylottman</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/casseylottman"/>
    <language>en</language>
    <item>
      <title>npx eleventy !== npx @11ty/eleventy</title>
      <dc:creator>Cassey Lottman</dc:creator>
      <pubDate>Wed, 07 Apr 2021 21:38:09 +0000</pubDate>
      <link>https://forem.com/casseylottman/npx-eleventy-npx-11ty-eleventy-1dk4</link>
      <guid>https://forem.com/casseylottman/npx-eleventy-npx-11ty-eleventy-1dk4</guid>
      <description>&lt;p&gt;The other day when I went to add a post to &lt;a href="https://cassey.dev/til"&gt;my TIL blog&lt;/a&gt;, I got a scary error message. The site runs using the static site generator &lt;a href="https://www.11ty.dev/"&gt;Eleventy&lt;/a&gt;, but I got a warning when I tried to start up the site that the command I had just run was not the static site generator at all. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg4n600hgmf9pdy4787t2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg4n600hgmf9pdy4787t2.png" alt="a screenshot of console output from the command 'npx eleventy --serve', with a message below that reads 'Atencion! This package has nothing to do with the eleventy static site generator. Most likely, you wanted to install the @11ty/eleventy package instead of this. Atencion! command not found: eleventy'" width="800" height="212"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Instead, it seemed I had run a package called &lt;a href="https://www.npmjs.com/package/eleventy"&gt;eleventy&lt;/a&gt; that is completely unaffiliated with the static site generator, which is listed on NPM as &lt;a href="https://www.npmjs.com/package/@11ty/eleventy"&gt;@11ty/eleventy&lt;/a&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  How did this happen?
&lt;/h2&gt;

&lt;p&gt;My package.json used &lt;code&gt;npx eleventy&lt;/code&gt; in its build/start scripts, when it should have used &lt;code&gt;npx @11ty/eleventy&lt;/code&gt; as specified in the &lt;a href="https://www.11ty.dev/docs/usage/"&gt;usage docs&lt;/a&gt;. You can &lt;a href="https://github.com/clottman/cassey-on-eleventy/commit/4c923bf1baca122159db17bafbd251fd0c264924#diff-7ae45ad102eab3b6d7e7896acd08c427a9b25b346470d7bc6507b6481575d519"&gt;see the changes on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npx eleventy&lt;/code&gt; was being used from the very first commit to my site, which I re-wrote in Eleventy in June of 2019. I had never encountered issues before, and none of the packages involved had changed names recently.&lt;/p&gt;

&lt;h2&gt;
  
  
  Okay, so why does this work most of the time?
&lt;/h2&gt;

&lt;p&gt;Usually, when I'm setting up to run an Eleventy project in a new workspace, I run &lt;code&gt;npm install&lt;/code&gt;, then &lt;code&gt;npm start&lt;/code&gt;. If you've forgotten to run &lt;code&gt;npm install&lt;/code&gt;, and also don't have Eleventy installed globally on your system, you might see that &lt;code&gt;npx eleventy&lt;/code&gt; will try to use the wrong package.&lt;/p&gt;

&lt;h2&gt;
  
  
  But why??
&lt;/h2&gt;

&lt;p&gt;To understand what happened, we need to look at how &lt;code&gt;npx&lt;/code&gt; works. The &lt;a href="https://github.com/npm/npx#readme"&gt;readme for npx&lt;/a&gt; was really helpful for me here. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;npx&lt;/code&gt; tries to find a command name in $PATH (so, globally installed modules), or in local project binaries, which means specifically, in an entry at the key &lt;code&gt;bin&lt;/code&gt; in &lt;code&gt;package.json&lt;/code&gt;. The commad name defined in &lt;code&gt;bin&lt;/code&gt; doesn't need to match the package name. For example, the package &lt;code&gt;@11ty/eleventy&lt;/code&gt; has one command defined, that's just called &lt;code&gt;eleventy&lt;/code&gt;. If you call &lt;code&gt;npx&lt;/code&gt; using the name of a package, &lt;code&gt;npx&lt;/code&gt; will try to guess which command from that package you want - so if you do &lt;code&gt;npx @11ty/eleventy&lt;/code&gt;, it will guess that you mean to run the one command that's defined, &lt;code&gt;eleventy&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;So, if you've already installed &lt;code&gt;@11ty/eleventy&lt;/code&gt; locally or globally, you can run &lt;code&gt;npx eleventy&lt;/code&gt; and get the version on your machine - a nice JavaScript static site generator. &lt;/p&gt;

&lt;p&gt;If you don't have the static site generator installed locally or globally, and you run &lt;code&gt;npx eleventy&lt;/code&gt;, &lt;code&gt;npx&lt;/code&gt; will look to the NPM registry and try to find a package there matching the name you entered - just &lt;code&gt;eleventy&lt;/code&gt;. It will pull down the package and try to run a command defined in it, and at least currently, find that there is no command for it to run. The package &lt;code&gt;eleventy&lt;/code&gt; has a postinstall script that runs, warning you that you just installed a package that is not the popular static site generator.&lt;/p&gt;

&lt;h2&gt;
  
  
  So what do I do?
&lt;/h2&gt;

&lt;p&gt;If you're using &lt;code&gt;npx eleventy&lt;/code&gt; in your build/run scripts or directly on the command line, update those to be &lt;code&gt;npx @11ty/eleventy&lt;/code&gt; to make sure you don't accidentally fetch and execute the entirely wrong package. &lt;/p&gt;

&lt;p&gt;It also seems like a good idea more generally when using &lt;code&gt;npx&lt;/code&gt; to prefer using the fully qualified package name when you can, instead of the command name from &lt;code&gt;bin&lt;/code&gt;. If there is just one &lt;code&gt;bin&lt;/code&gt; command defined or the name of the command you want matches the package name, this should work. This way, you can avoid being surprised by a command that executes code you didn't actually mean to even download, let alone run.&lt;/p&gt;



&lt;h2&gt;
  
  
  PS
&lt;/h2&gt;

&lt;p&gt;Did you know that &lt;a href="https://www.unabridgedsoftware.com/"&gt;Unabridged Software&lt;/a&gt;, where I work, is part of the Eleventy &lt;a href="https://www.11ty.dev/super-professional-business-network/"&gt;Super Professional Business Network&lt;/a&gt;? If you need help with your Eleventy site or want to have one built and don't have the time, get in touch.&lt;/p&gt;

</description>
      <category>eleventy</category>
      <category>node</category>
      <category>npm</category>
    </item>
    <item>
      <title>Adding a field to your sign-up form with Devise</title>
      <dc:creator>Cassey Lottman</dc:creator>
      <pubDate>Fri, 19 Feb 2021 22:39:48 +0000</pubDate>
      <link>https://forem.com/casseylottman/adding-a-field-to-your-sign-up-form-with-devise-10i1</link>
      <guid>https://forem.com/casseylottman/adding-a-field-to-your-sign-up-form-with-devise-10i1</guid>
      <description>&lt;p&gt;Devise is the go-to solution for user authentication in Ruby on Rails, and it's extremely customizable. There is documentation galore on everything you can do with it, but when I first started using it, I found it all a bit overwhelming. &lt;/p&gt;

&lt;p&gt;I wanted to have a basic sign-up flow and add one custom field that users would be required to enter in order to create an account. Here are the steps I took, starting with installing Devise. &lt;/p&gt;

&lt;h2&gt;
  
  
  Install Devise
&lt;/h2&gt;

&lt;p&gt;Here we're following the &lt;a href="https://github.com/heartcombo/devise#getting-started"&gt;Devise Getting Started guide&lt;/a&gt; directly.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add &lt;code&gt;gem 'devise'&lt;/code&gt; to your Gemfile&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;bundle install&lt;/code&gt; to install it&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;rails generate devise:install&lt;/code&gt;
Read the instructions here and make any changes you need to make - probably setting including setting the default Action Mailer URL in &lt;code&gt;config/environments/development.rb&lt;/code&gt;.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;action_mailer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;default_url_options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;host: &lt;/span&gt;&lt;span class="s1"&gt;'localhost'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;port: &lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Step 4 of the instructions, at least at time of writing, tells you to optionally run &lt;code&gt;rails g devise:views&lt;/code&gt;. Don't do this yet; we just want to bring in the views that we intend to customize little by little. &lt;/p&gt;

&lt;h2&gt;
  
  
  Run the model generator for Devise
&lt;/h2&gt;

&lt;p&gt;If you want to use the User model, you'll run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;rails&lt;/span&gt; &lt;span class="n"&gt;generate&lt;/span&gt; &lt;span class="n"&gt;devise&lt;/span&gt; &lt;span class="no"&gt;User&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As mentioned in the getting started guide, this will create a model if one doesn't already exist, and configure it with the default Devise modules. &lt;/p&gt;

&lt;p&gt;Check your User model to make sure you like the included modules, and add more if you want to. If you do, you'll need to uncomment the corresponding sections in migration file.&lt;/p&gt;

&lt;h3&gt;
  
  
  Add the additional column you want to save on sign up
&lt;/h3&gt;

&lt;p&gt;I knew when I was getting set up with Devise that I'd want to save a the user's name (as in Cassey) along with their email and password on sign-up. So, I went ahead and added the column I wanted to the generated &lt;code&gt;devise_create_users&lt;/code&gt; migration. A new user must have a name, so I made it non-nullable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;t.string :name, null: false
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also create a separate migration to add the extra column if you want, to make it clear what what you added to the base Devise configuration.&lt;/p&gt;

&lt;p&gt;When you're ready, run &lt;code&gt;rails db:migrate&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Run the app. &lt;/p&gt;

&lt;h2&gt;
  
  
  Test your routes
&lt;/h2&gt;

&lt;p&gt;Run your Rails app, and make sure that you can navigate to the new user registration path - by default &lt;code&gt;/users/sign_up&lt;/code&gt;. When you're there, you should see a simple form that asks the user for their email, their password, and a password confirmation. &lt;/p&gt;

&lt;p&gt;You might want something like this in your main layout, so that users can sign in if they're not signed in already, or sign out. The &lt;code&gt;current_user&lt;/code&gt; variable is available automagically thanks to Devise.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;%&lt;/span&gt; &lt;span class="na"&gt;if&lt;/span&gt; &lt;span class="na"&gt;current_user&lt;/span&gt; &lt;span class="err"&gt;%&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;%=&lt;/span&gt; &lt;span class="na"&gt;link_to&lt;/span&gt; &lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="na"&gt;Sign&lt;/span&gt; &lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="err"&gt;",&lt;/span&gt; &lt;span class="na"&gt;destroy_user_session_path&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="na"&gt;method:&lt;/span&gt; &lt;span class="na"&gt;:delete&lt;/span&gt;  &lt;span class="err"&gt;%&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;%&lt;/span&gt; &lt;span class="na"&gt;else&lt;/span&gt; &lt;span class="err"&gt;%&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;%=&lt;/span&gt; &lt;span class="na"&gt;link_to&lt;/span&gt; &lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="na"&gt;Sign&lt;/span&gt; &lt;span class="na"&gt;up&lt;/span&gt;&lt;span class="err"&gt;",&lt;/span&gt; &lt;span class="na"&gt;new_user_registration_path&lt;/span&gt; &lt;span class="err"&gt;%&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;%&lt;/span&gt; &lt;span class="na"&gt;end&lt;/span&gt; &lt;span class="err"&gt;%&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Watch out for the &lt;code&gt;method&lt;/code&gt; on the sign out link - it needs to be &lt;code&gt;DELETE&lt;/code&gt;, and won't work if you try to make the request with &lt;code&gt;POST&lt;/code&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  Bring in the controllers you need to customize
&lt;/h2&gt;

&lt;p&gt;If we try to submit the form at this point, it won't work! We'll see &lt;code&gt;SQLite3::ConstraintException: NOT NULL constraint failed: users.name&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;We need to modify the controller that accepts sign ups, in order to actually save the &lt;code&gt;name&lt;/code&gt; field to the database. &lt;/p&gt;

&lt;p&gt;At first, when you install Devise, the views and even the controllers that will be used are all located in the engine itself - not in your app where you can edit them directly. You can use a generator to bring copies into your app that you can edit.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rails generate devise:controllers users -c registrations
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create a file at &lt;code&gt;controllers/users/registrations_controller.rb&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;registrations_controller.rb&lt;/code&gt;, we have a class &lt;code&gt;Users::RegistrationsController&lt;/code&gt; that inherits from &lt;code&gt;Devise::RegistrationsController&lt;/code&gt;. All the methods in it are commented out - and as long as you leave them commented out, the behavior of the class will fall back to what's in the parent class, aka Devise's default behaviors.&lt;/p&gt;

&lt;p&gt;To make sure this class is actually used for Devise routes, we need to change the settings for &lt;code&gt;devise_for&lt;/code&gt; in &lt;code&gt;config/routes.rb&lt;/code&gt;, like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;devise_for&lt;/span&gt; &lt;span class="ss"&gt;:users&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:controllers&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;registrations: &lt;/span&gt;&lt;span class="s1"&gt;'users/registrations'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Okay, back to &lt;code&gt;Users::RegistrationsController&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Uncomment the following lines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;before_action&lt;/span&gt; &lt;span class="ss"&gt;:configure_sign_up_params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;only: &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:create&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;
  &lt;span class="k"&gt;super&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;configure_sign_up_params&lt;/span&gt;
  &lt;span class="n"&gt;devise_parameter_sanitizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;permit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:sign_up&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;keys: &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:attribute&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We need to make a change here, to the &lt;code&gt;configure_sign_up_params&lt;/code&gt; method, to get rid of the placeholder &lt;code&gt;:attribute&lt;/code&gt; that's helping us know what to put where, and add in the form field that we want to allow through the controller.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gd"&gt;-   devise_parameter_sanitizer.permit(:sign_up, keys: [:attribute])
&lt;/span&gt;&lt;span class="gi"&gt;+   devise_parameter_sanitizer.permit(:sign_up, keys: [:name])
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Bring the views into your app to customize them
&lt;/h2&gt;

&lt;p&gt;Our sign up form is pretty basic but mostly functional (you'll probably want to customize the design a bit soon), but it's  still not asking the user for their name. So, let's copy the view over from the Devise engine using the generator.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rails generate devise:views users -v registrations
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After running this command, you should see a new folder under &lt;code&gt;views&lt;/code&gt;: &lt;code&gt;views/users&lt;/code&gt;, which contains &lt;code&gt;./registrations&lt;/code&gt; (and &lt;code&gt;./shared&lt;/code&gt;, if this is the first time you've generated views with Devise). The &lt;code&gt;views/users/registrations&lt;/code&gt; folder will have two files, one for &lt;code&gt;edit&lt;/code&gt;ing an account registration, and one for a &lt;code&gt;new&lt;/code&gt; sign up. &lt;/p&gt;

&lt;p&gt;In &lt;code&gt;views/users/registrations/new.html.erb&lt;/code&gt;, we see the code that was generating the form we saw earlier. Let's add a field for the user's &lt;code&gt;name&lt;/code&gt;, matching the structure of the generated parts of the form:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div class="field"&amp;gt;
  &amp;lt;%= f.label :name %&amp;gt;&amp;lt;br /&amp;gt;
  &amp;lt;%= f.text_field :name %&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you reload the &lt;code&gt;/users/sign_up&lt;/code&gt; in the browser, you should see your new name field! You should be able to submit it at this point, too, since we've already made changes in the controller to allow through the &lt;code&gt;name&lt;/code&gt; parameter.&lt;/p&gt;

&lt;p&gt;Happy customization! &lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
      <category>devise</category>
    </item>
    <item>
      <title>Let the browser do what browsers do: a story about accessibility on Medium</title>
      <dc:creator>Cassey Lottman</dc:creator>
      <pubDate>Fri, 23 Oct 2020 22:42:14 +0000</pubDate>
      <link>https://forem.com/casseylottman/let-the-browser-do-what-browsers-do-a-story-about-accessibility-on-medium-51o3</link>
      <guid>https://forem.com/casseylottman/let-the-browser-do-what-browsers-do-a-story-about-accessibility-on-medium-51o3</guid>
      <description>



&lt;p&gt;Hello, friends! Perhaps you have already heard an old web accessibility accessibility principle: developers should rely on browser &lt;a href="https://developers.google.com/web/fundamentals/accessibility/semantics-builtin"&gt;semantics&lt;/a&gt; as much as possible. &lt;/p&gt;

&lt;p&gt;Maybe you have heard it in the form of &lt;a href="https://www.w3.org/TR/using-aria/#firstrule"&gt;The First Rule of ARIA&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you can use a native HTML element [HTML51] or attribute with the semantics and behavior you require already built in, instead of re-purposing an element and adding an ARIA role, state or property to make it accessible, then do so.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The rules of ARIA generally describe how to make interactive aspects of your site accessible. In this post, we're going to look at how overriding browser &lt;em&gt;styling&lt;/em&gt; defaults can also lead you astray, accessibility-wise. &lt;/p&gt;

&lt;p&gt;This story begins with me, reading some interesting blog posts on Medium.com, on my phone. I use the browser's built-in text magnification, because even with glasses, vision remains a challenge for me. (Specifically, I use Brave and Chrome on Android, with text magnification of 150%.) I had been noticing that link underlines on Medium posts made the words look as if they were struck out. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fnjjyr32i1pim8dbzo0ei.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fnjjyr32i1pim8dbzo0ei.png" alt="a screenshot of a Medium post on Chrome on Android. The link underlines appear as strikeouts, about 1/4 the way up the word" width="800" height="1644"&gt;&lt;/a&gt;&lt;/p&gt;
On Chrome on Android, this isn't a strikeout - these are misbehaving link underlines.



&lt;p&gt;(The story ends with me procrastinating a month to write this post, and in the meantime, Medium has actually fixed the issue. If you change your text magnification settings and go looking for it, you won't find it. Took you a while, &lt;em&gt;*cough* six years&lt;/em&gt; but good job, Medium! The screenshots for this piece were all collected on October 1st, 2020, and shared in two different slacks where I was trying to parse through the issue with the help of friends.) &lt;/p&gt;

&lt;p&gt;I opened up the same post in a browser to inspect the HTML and CSS, and was surprised: on desktop Firefox, the links were unmarked entirely! Surely someone had noticed this, right? But the misplaced underlines had been happening for me for quite a while on mobile; what was going on?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ftfksrmc960hp92s77wyb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ftfksrmc960hp92s77wyb.png" alt="a medium article viewed in firefox, with the dev tools open. There are no link underlines visible in the post" width="800" height="430"&gt;&lt;/a&gt;&lt;/p&gt;
In desktop (macOS Catalina) Firefox, the link underlines have vanished completely!



&lt;p&gt;Eventually, with the help of folks in some tech slacks I'm in, I realized others &lt;em&gt;weren't&lt;/em&gt; seeing what I was seeing. What?!? Then I remembered I also use vision accommodations in desktop browsers. Specifically, I have a &lt;a href="https://support.mozilla.org/en-US/kb/font-size-and-zoom-increase-size-of-web-pages"&gt;minimum font size&lt;/a&gt; set at the browser level, and all sites I visit have to display text no smaller than that font, regardless of what the developers wanted. When I turned that off, the underlines snapped back into their normal places. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fomxdd79ie7q6yrf9dw8e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fomxdd79ie7q6yrf9dw8e.png" alt="In mobile chrome, at 100% text magnification, the underlines are present and in their proper places" width="800" height="1644"&gt;&lt;/a&gt;&lt;/p&gt;
In mobile chrome, at 100% text magnification, the underlines are present and in their proper places



&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fwexkyzwhloq596ivgnc0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fwexkyzwhloq596ivgnc0.png" alt="In Chrome on desktop mac, with no font size overrides active, the text underlines are present and in their proper places" width="800" height="386"&gt;&lt;/a&gt;&lt;/p&gt;
In Chrome on macOS Catalina, with no font size overrides active, the text underlines are present and in their proper places!



&lt;p&gt;Something you might have noticed in the browser tools of those screenshots (or you might not because the screenshot is blurry; sorry, I didn't copy out the HTML and it's gone forever now) is that Medium is doing some funny-business with the underlines. Each of the links has &lt;code&gt;text-decoration: none&lt;/code&gt;, and the underline is being provided through a &lt;code&gt;background-image&lt;/code&gt; which is an SVG. &lt;/p&gt;

&lt;p&gt;Someone in one of the slacks I was documenting my perplexity in pointed me to this post: &lt;a href="https://medium.design/crafting-link-underlines-on-medium-7c03a9274f9"&gt;"Crafting Link Underlines on Medium"&lt;/a&gt;, posted on Medium's official design blog way back in 2014. In this post, a designer at Medium documented the design team's frustration with browser built-in underlines, and what considerations went in to building "better" underlines. The frustration seems to be that the underlines were a bit bolder than the design team would like; to my non-designer (and admittedly, lower-than-average vision) eyes, a comparison of the previous and new-then underlines look very similar, and the previous ones certainly don't offend me enough that I'd go to much effort to change them. The author went on to document implementations that the team had considered and rejected, and the one they chose: some code that looked suspiciously like what I was seeing in the developer tools of my browser on October 1, 2020.&lt;/p&gt;

&lt;p&gt;Here is where I get a little snarky, because I was going down a deep rabbit hole to figure out why these underlines behaved so poorly for me, then was a bit ragey to find it was yet another broken thing resulting from site builders not anticipating &amp;amp; accounting for the assistive technology I use. And then, I opened this post, from Medium, about the exact thing that has been causing this problem for 6 years now, and it started like this: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;How hard could it be to draw a horizontal line on the screen?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;insert very snarky comment right about here&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Another standout line, that many others before me have highlighted, goes like this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Web design always seemed like this, too: finding convoluted, “dirty” solutions to often simple problems, using a very limited set of tools. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;insert mirthless laugh here&lt;/em&gt; &lt;/p&gt;

&lt;p&gt;To be fair to the Medium design team, they &lt;em&gt;did&lt;/em&gt; consider some accessibility issues in the implementation they eventually chose. &lt;/p&gt;

&lt;p&gt;Their list of criteria for the final design includes these lines: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We adjust the sizes of fonts for tablets and mobile phones.&lt;br&gt;
We fall back to a default system font for when we decide that our type doesn’t support all the characters in a given language.&lt;br&gt;
Some people zoom in (or zoom out) their browsers.&lt;br&gt;
Some people use uncommon browsers.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;People &lt;em&gt;do&lt;/em&gt; zoom in &amp;amp; out their browsers, and good site designs should account for that, and not break. But some people, like me, find that browser zoom is not the best solution for reading text better. If you zoom your browser, you might need to adjust the zoom level on every page you visit. Browser zoom also means that ads and the images accompanying posts have also gotten bigger, so you're going to need to scroll more. (In my case, I can typically see images just fine, except for tiny profile images. I really just need the text to be bigger, and when it's already huge, to not get any bigger. One might say... to be always bigger than a minimum size.)&lt;/p&gt;

&lt;p&gt;So here we have a case where a design/dev team wanted to customize the styling of a built-in browser &lt;a href="https://developers.google.com/web/fundamentals/accessibility/semantics-builtin#affordances"&gt;affordance&lt;/a&gt;. And they &lt;em&gt;did&lt;/em&gt; want to ensure the thing they were building would still be accessible. But, they failed to account for one particular way of making the web accessible that users with low vision might use, and made their experience much worse. (It's distracting that many of the words of some posts appear to be crossed out, as in mobile browsers, and it's even more confusing to have links not visually indicated at all, as in desktop Firefox.) &lt;/p&gt;

&lt;p&gt;How has Medium fixed the issue? Took out most of their custom &lt;code&gt;background-image&lt;/code&gt; stuff, basically. Now they have a class on all their links, adding &lt;code&gt;text-decoration: underline&lt;/code&gt;. &lt;em&gt;Wait Cassey, you said that's built-in, why do they need that?&lt;/em&gt; Only because when cleaning up their legacy code that did the &lt;code&gt;background-image&lt;/code&gt; stuff, they didn't also axe the CSS that did &lt;code&gt;a { text-decoration: none }&lt;/code&gt;, which removes that handy browser built-in.&lt;/p&gt;

&lt;p&gt;You can &lt;a href="https://adrianroselli.com/2016/06/on-link-underlines.html"&gt;read more about link underlines&lt;/a&gt; in this post from &lt;a href="https://twitter.com/aardrian"&gt;@aardrian&lt;/a&gt; who does not (in a 2016 blog post, with a few updates since then) take for granted, like I do, that link underlines are obviously good and important, and considers a whole host of reasons people like and dislike them, and what is best for accessibility. (Spoiler, they conclude link underlines are best.)&lt;/p&gt;

</description>
      <category>a11y</category>
      <category>design</category>
      <category>inclusion</category>
    </item>
    <item>
      <title>How Animal Crossing is Bringing Glitch Together</title>
      <dc:creator>Cassey Lottman</dc:creator>
      <pubDate>Fri, 27 Mar 2020 17:58:35 +0000</pubDate>
      <link>https://forem.com/glitch/how-animal-crossing-is-bringing-glitch-together-3j8d</link>
      <guid>https://forem.com/glitch/how-animal-crossing-is-bringing-glitch-together-3j8d</guid>
      <description>&lt;p&gt;Last Friday, I saw a tweet from my manager that made me a bit nervous. I wanted to engage with it, but would it be crossing a line if I did? I wasn't sure, so I tentatively messaged him in Slack to find out: "Was that tweet for me, too?"&lt;/p&gt;

&lt;p&gt;The tweet in question contained a Nintendo Switch friend code, and coincided with the much-hyped launch of Animal Crossing: New Horizons. I was looking forward to the game, too, and wasn't really sure what being Animal Crossing friends would mean, but it sounded very exciting.&lt;/p&gt;

&lt;p&gt;My manager replied that it was absolutely fine for us to be friends in the game, and informed me that it meant we could send each other gifts, perhaps to exchange types of fruit that can be planted for big in-game rewards. &lt;/p&gt;

&lt;p&gt;Later that day, I joined the #gaming channel in the Glitch slack, where I discovered many other coworkers excited to play Animal Crossing. There was even already a thread someone to share friend codes, and another post where we could use reacji to indicate what type of fruit our island was growing. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fsw2jjy5zqlch9dph6pd4.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fsw2jjy5zqlch9dph6pd4.PNG" alt='A slack message in which Keith Kurson asks "what is everyone growing on their islands?" Responses are in the form of emoji reacts: 5 oranges, 1 cherry, 3 apples, 1 peach, and 4 pears' width="707" height="173"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After work, I jumped right in to the new game. In this new release of Animal Crossing, your character has just moved to a previously uninhabited island alongside a few anthropomorphic animals. You can catch bugs, go fishing, and decorate your tent and island with all sorts of furniture. The game progresses in real time (an in-game day really lasts 24 hours), and new things to do and explore slowly unlock over time.&lt;/p&gt;

&lt;p&gt;Starting on Day 2, players have access to an airport which they can use to visit other player's islands, or host guests themselves. After you've exchanged a visit with a friend, you can also send that friend letters and packages that they'll see the next time they're online.&lt;/p&gt;

&lt;p&gt;The #gaming channel in Slack has been very active over the last week. Posts range from memes about the game, to screenshots of our own unique creations, to in-depth discussions of the best tarantula-catching technique. Someone even shared &lt;a href="https://acnh-turnip-prices.glitch.me/"&gt;an Animal Crossing-themed Glitch app&lt;/a&gt; created by &lt;a href="https://glitch.com/@mythmon"&gt;one of our users&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1242881381404835840-104" src="https://platform.twitter.com/embed/Tweet.html?id=1242881381404835840"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1242881381404835840-104');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1242881381404835840&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;There are around 15 folks who have the game, but we're not the only ones having fun. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F5m3a5wj30lxsegizlzdv.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F5m3a5wj30lxsegizlzdv.PNG" alt="A slack message from Emmett Walsh, reading &amp;quot;I'm loving this channel right now, it's like I own the game&amp;quot;" width="785" height="151"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The adorable virtual dodo pilots of the in-game airline have also been quite busy, ferrying players and packages back and forth each night for collaborative adventures. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F2izv8l7sx79rfl41ak8e.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F2izv8l7sx79rfl41ak8e.jpg" alt="3 player characters from Animal Crossing stand near a house in the game" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Through the game, I've gained a deeper appreciation for many coworkers: Potch is a gracious host, with a dedicated fenced-in area to make clear what he's giving away to any guests. Melissa is a talented pixel fashion designer, with an elaborate cosplay costume for their character. Osmose has cherries, and since cherries were the last fruit I needed to complete my collection of all the types of trees, I really appreciate that about Osmose. &lt;/p&gt;

</description>
    </item>
    <item>
      <title>Opening a new window from a Firefox Add-On</title>
      <dc:creator>Cassey Lottman</dc:creator>
      <pubDate>Sun, 15 Mar 2020 21:51:58 +0000</pubDate>
      <link>https://forem.com/casseylottman/opening-a-new-window-from-a-firefox-add-on-309k</link>
      <guid>https://forem.com/casseylottman/opening-a-new-window-from-a-firefox-add-on-309k</guid>
      <description>&lt;p&gt;Last year, I made &lt;a href="https://www.cassey.dev/posts/2019-05-30-glitch-app-to-project-ext/"&gt;my first couple browser extensions&lt;/a&gt;! Both were built to solve immediate needs I have: one to &lt;a href="https://glitch.com/~app-to-project-extension"&gt;go between the various representations of a Glitch project&lt;/a&gt; (the project page at glitch.com/~projectname, the editor, and the running code at projectname.glitch.me), and one to add things to my &lt;a href="https://pinboard.in"&gt;Pinboard&lt;/a&gt; bookmarks. &lt;/p&gt;

&lt;p&gt;The code that opens the Add to Pinboard page originated as &lt;a href="https://pinboard.in/howto/#saving"&gt;code for a bookmarklet, provided by Pinboard&lt;/a&gt;, but I like extensions better. Bookmarklets show up in my browser's Bookmarks toolbar, which I usually keep hidden. Extensions show up right next to the address bar, in a single line. &lt;/p&gt;

&lt;p&gt;I use my Pinboard extension pretty regularly&lt;sup&gt;1&lt;/sup&gt;, in both &lt;a href="https://chrome.google.com/webstore/detail/pinboard-it/mafapkanfcjklkaloepbphjpmfefobbj"&gt;Chrome&lt;/a&gt; and &lt;a href="https://addons.mozilla.org/en-US/firefox/addon/add-to-pinboard/"&gt;Firefox as an Add-On&lt;/a&gt;. But my Firefox version was annoying: when I clicked the extension, I'd see a little warning that a popup had been blocked, and would I like to allow it to be opened anyways? Yes, I would, every time. But the only options available in the little menu were to always allow popups on whatever site I was trying to save, or allow it just this once. That wasn't great- I might want to allow my Pinboard add-on to open a popup so I can save a link to a cute dress in an online shopping website, but I wouldn't want that shopping site to start sending me its own popups.&lt;/p&gt;

&lt;h2&gt;
  
  
  How can I allow my extension to always open a popup window in Firefox?
&lt;/h2&gt;

&lt;p&gt;The answer turned out to be something I needed to change in code. &lt;/p&gt;

&lt;p&gt;Previously, my extension used the exact same code as the bookmarklet, which called &lt;code&gt;open('https://example.com')&lt;/code&gt; to open the new tab. &lt;/p&gt;

&lt;p&gt;If I changed my tab-opening code to use the APIs that exist especially for browser extensions, the popup would not be blocked.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;chrome.tabs.create({ url: 'https://example.com' });&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You can see &lt;a href="https://glitch.com/edit/#!/pinboard-extension?path=extension/background.js:1:0"&gt;the full source code for my extension on Glitch&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Thanks to these friends in &lt;a href="https://discourse.mozilla.org/t/avoid-popup-blocker/31549"&gt;a Mozilla forum question in 2018&lt;/a&gt; for pointing me in the right direction!&lt;/p&gt;

&lt;h2&gt;
  
  
  Addendum
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Judging by the active user stats, I am probably the only person using my extension, albeit from two different computers. I agree with Robin Sloan that &lt;a href="https://www.robinsloan.com/notes/home-cooked-app/"&gt;an app can be a home-cooked meal&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>extension</category>
      <category>firefox</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Testing Modern React with Enzyme Shallow</title>
      <dc:creator>Cassey Lottman</dc:creator>
      <pubDate>Wed, 11 Mar 2020 22:03:32 +0000</pubDate>
      <link>https://forem.com/casseylottman/testing-modern-react-with-enzyme-shallow-4l1f</link>
      <guid>https://forem.com/casseylottman/testing-modern-react-with-enzyme-shallow-4l1f</guid>
      <description>&lt;h2&gt;
  
  
  tl;dr:
&lt;/h2&gt;

&lt;p&gt;I learned recently that the only way to use Enzyme to test a React component that relies on a &lt;code&gt;useContext&lt;/code&gt; hook appears to be to use &lt;code&gt;render&lt;/code&gt; or &lt;code&gt;mount&lt;/code&gt;, not &lt;code&gt;shallow&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  more detail:
&lt;/h2&gt;

&lt;p&gt;I've been helping some coworkers with thorny questions about testing React components lately, and found some surprising issues I hadn't seen blogged about elsewhere. Specifically, let's dive in to testing with the &lt;code&gt;shallow&lt;/code&gt; render method from Enzyme.&lt;/p&gt;

&lt;p&gt;Assumptions you can make for this post include: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I'm talking about React with hooks, so 16.8+&lt;/li&gt;
&lt;li&gt;I'm talking about using the Adapter from Enzyme for testing&lt;/li&gt;
&lt;li&gt;I've tested with mochapack and jest and gotten the same results&lt;/li&gt;
&lt;li&gt;I am not an expert, nor a maintainer of any of the above libraries. &lt;/li&gt;
&lt;li&gt;I do use React for work, and have a basic familiarity with React testing libraries.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  General Concerns about &lt;code&gt;shallow&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Famous JavaScript guy Kent C. Dodds says to &lt;a href="https://kentcdodds.com/blog/why-i-never-use-shallow-rendering"&gt;never use shallow rendering&lt;/a&gt;, and he doesn't even mention the &lt;code&gt;useContext&lt;/code&gt; weirdness I'm about to describe. He makes some great points; I recommend giving it a read.&lt;/p&gt;

&lt;h3&gt;
  
  
  If I do use &lt;code&gt;shallow&lt;/code&gt;, I still can use &lt;code&gt;React.Context&lt;/code&gt;, right?
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://enzymejs.github.io/enzyme/docs/api/shallow.html"&gt;The docs for &lt;code&gt;shallow&lt;/code&gt;&lt;/a&gt; imply that you can still use context in shallowly rendered components, by providing the &lt;code&gt;wrappingComponent&lt;/code&gt; option. &lt;strong&gt;&lt;em&gt;This is misleading.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;options.wrappingComponent&lt;/code&gt;: (&lt;code&gt;ComponentType&lt;/code&gt; [optional]): A component that will render as a parent of the node. It can be used to provide context to the node, among other things. See the getWrappingComponent() docs for an example. Note: wrappingComponent must render its children.&lt;br&gt;
&lt;code&gt;options.wrappingComponentProps&lt;/code&gt;: (&lt;code&gt;Object&lt;/code&gt; [optional]): Initial props to pass to the wrappingComponent if it is specified.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The only way to test a component with Enzyme that relies on a &lt;code&gt;useContext&lt;/code&gt; hook appears to be to use &lt;code&gt;render&lt;/code&gt; or &lt;code&gt;mount&lt;/code&gt;, not &lt;code&gt;shallow&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I made &lt;a href="https://codesandbox.io/s/priceless-driscoll-j45bv"&gt;a CodeSandbox of every method I could think of to potentially use &lt;code&gt;useContext&lt;/code&gt; with &lt;code&gt;shallow&lt;/code&gt;&lt;/a&gt;, all of which fail.&lt;/p&gt;

&lt;p&gt;Later, I found this &lt;a href="https://github.com/enzymejs/enzyme/issues/2176"&gt;longstanding issue in the Enzyme repository describing this exact issue&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Here's &lt;a href="https://github.com/enzymejs/enzyme/issues/2176#issuecomment-532361526"&gt;a helpful comment from another user with suggested workarounds&lt;/a&gt;; &lt;br&gt;
here's &lt;a href="https://github.com/enzymejs/enzyme/issues/2176#issuecomment-532461718"&gt;a maintainer confirming that fixing this would take substantial effort and probably won't happen&lt;/a&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  What about context from React-Redux?
&lt;/h2&gt;

&lt;p&gt;You might think you can avoid this by using React-Redux as your context provider, instead of React's built-in context. You might think this is supported, since the code sample in &lt;a href="https://enzymejs.github.io/enzyme/docs/api/ShallowWrapper/getWrappingComponent.html"&gt;the Enzyme docs for ShallowWrapper-getWrappingComponent&lt;/a&gt; show exactly this. You would be wrong, since React-Redux now also uses &lt;code&gt;useContext&lt;/code&gt; for its operations. I have a test demonstrating this in &lt;a href="https://codesandbox.io/s/priceless-driscoll-j45bv"&gt;my Code Sandbox repro&lt;/a&gt;. (Look for "can use a react-redux provider"). (h/t to coworker Greg, who separately stumbled on this problem this week, for pointing this out!)&lt;/p&gt;

&lt;p&gt;I hope this post saves you time and frustration. (No fewer than 3 members of my team spent several hours each on this, just this week.) Happy testing! &lt;/p&gt;

</description>
      <category>react</category>
      <category>testing</category>
      <category>enzyme</category>
    </item>
    <item>
      <title>My Web Creations from 2019</title>
      <dc:creator>Cassey Lottman</dc:creator>
      <pubDate>Thu, 02 Jan 2020 17:33:23 +0000</pubDate>
      <link>https://forem.com/casseylottman/my-web-creations-from-2019-21m3</link>
      <guid>https://forem.com/casseylottman/my-web-creations-from-2019-21m3</guid>
      <description>&lt;p&gt;I coded quite a bit this year - I'm a full-time software developer, after all. I didn't just code for work, though - this year, like last year, I branched out and also wrote code outside of projects that were strictly for work. It certainly helps that Glitch encourages employees to spend some work time working on whatever personal projects we'd like, as long as we build on Glitch. While not all of the work for these projects took place during my work day, you'll notice that most of them were built on Glitch, because Glitch makes it easy to start creating new things based on a starter project ("remix" in Glitch parlance) and get something instantly on the web without thinking about hosting at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  Accessibility Audit (for work)
&lt;/h2&gt;

&lt;p&gt;In my work at &lt;a href="https://glitch.com"&gt;Glitch.com&lt;/a&gt;, I was most excited this year to work on an accessibility audit for the parts of the site my team is responsible for, that is, everything except the editor portions. Through the audit and tackling the implementation of accessibility improvements, I gained a deeper understanding of how to make sure the web is accessible to all users. I even returned to my alma mater as a guest lecturer on accessibility for a Design Studio class.&lt;/p&gt;

&lt;h2&gt;
  
  
  Eleventy
&lt;/h2&gt;

&lt;p&gt;This year was the first time I used &lt;a href="https://www.11ty.dev/docs/"&gt;Eleventy&lt;/a&gt;, and I ended up using it for a lot of different sites. Eleventy is a Javascript &lt;a href="https://davidwalsh.name/introduction-static-site-generators"&gt;static site generator&lt;/a&gt; created by a &lt;a href="https://twitter.com/zachleat"&gt;fellow Nebraskan&lt;/a&gt;. I like how easy it is to customize and how fast it is, but most of all, I love that it's written in Javascript, which is a language I use all the time. After moving off Wordpress.com, I first created my blog using Jekyll, a Ruby-based static site generator, but it's been years since I worked regularly with Ruby. I have an almost-working copy of my site ported to Hugo, but since I know even less Go than I do Ruby, it was frustrating to work with and I never finished.&lt;/p&gt;

&lt;h3&gt;
  
  
  cassey.dev
&lt;/h3&gt;

&lt;p&gt;My main personal site is now built with Eleventy! It was ported over in August from Jekyll hosted on GitHub Pages, and it now lives in Netlify. I never got around to adding a search feature, but the tagging system is much more flexible and easy to maintain than it was in the Jekyll version. Also, I didn't notice until too late that the generated URLs use a slightly different format than the old blog did, so there's a lot of broken links out there, mostly on my Twitter and Facebook. Other than that, I'm quite happy with how the site turned out.&lt;/p&gt;

&lt;h3&gt;
  
  
  TIL Blog
&lt;/h3&gt;

&lt;p&gt;Starting in June, I kept track of things I was learning about tech on an Eleventy site I built called &lt;a href="http://cassey-til.glitch.me/"&gt;cassey-til&lt;/a&gt;. The site also contains some learnings I recorded before creating the site, which I had been storing in a GitHub repository. Want your own &lt;strong&gt;T&lt;/strong&gt;oday &lt;strong&gt;I&lt;/strong&gt; &lt;strong&gt;L&lt;/strong&gt;earned blog? Head over to Glitch and &lt;a href="https://glitch.com/~til-blog/"&gt;remix my "TIL-Blog" project&lt;/a&gt;! I set it up so it will be easy to add your own author info and blog title, and you'll start with a blank slate in the posts directory. Follow the instructions in the readme for what to do after remixing.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://glitch.com/~link-tree-11ty"&gt;Link Trees with Eleventy&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;I built a few link tree-style sites this year, that is, standalone sites with nothing but a list of links on them. After building the first one, when I wanted to make another, I would remix a previous site and then edit a bunch of CSS colors, meta tags, and of course, the links themselves. After going through this manual process enough times, I created &lt;a href="https://glitch.com/~link-tree-11ty"&gt;a new template for my link trees&lt;/a&gt; using Eleventy. It pulls info for the meta tags and page title from a metadata file, and info on each link is pulled from a Javascript file and formatted uniformly into HTML.&lt;/p&gt;

&lt;p&gt;My link trees from this year include &lt;a href="https://lincoln-politics.glitch.me/"&gt;a list of the best stories captured by local activists in Lincoln, Nebraska&lt;/a&gt;, &lt;a href="https://art-i-like.glitch.me/"&gt;a list of my favorite artists&lt;/a&gt;, and &lt;a href="https://casseys-community-health-resources.glitch.me/"&gt;a list of resources on digital community health &amp;amp; moderation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Browser Extensions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://glitch.com/~app-to-project-extension"&gt;Glitch App to Project Extension&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;At the end of May, I worked on a browser extension to make it easy to go between the various representations of a project on Glitch: the project page (glitch.com/~soulpatch), the editor (&lt;a href="https://glitch.com/edit/#!/soulpatch"&gt;https://glitch.com/edit/#!/soulpatch&lt;/a&gt;), and the running app (soulpatch.glitch.me). I &lt;a href="https://www.cassey.dev/posts/2019-05-30-glitch-app-to-project-ext/"&gt;blogged about creating the App to Project extension&lt;/a&gt;, but the initial app was much more limited in features. It would take you from an app to a project page and vice versa, but not the editor. And, it only worked in Chrome. Later, I modified it to add a context menu that lets you choose which page you want to go to from any of the other pages, and made it run in Firefox. A coworker helped refactor the app and fixed a few bugs with it. Overall, the extension works great (I still use it basically every day) and it was a great learning experience.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://pinboard-extension.glitch.me/"&gt;Pinboard Extension&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;My first ever browser extension, built this year, was a simple extension to enable me to save the page I'm viewing to &lt;a href="https://pinboard.in"&gt;Pinboard&lt;/a&gt;. Pinboard is a bookmark manager I use to keep track of interesting stuff I find online. Its documentation includes code for a bookmarklet (a snippet of code that you drag to your bookmarks bar in Chrome, which will then run when you click it) to save new links to Pinboard. I don't like bookmarklets though - I prefer to keep my bookmarks bar hidden. So, I took the code from the bookmarklet and made it into a browser extension! &lt;a href="https://chrome.google.com/webstore/detail/pinboard-it/mafapkanfcjklkaloepbphjpmfefobbj"&gt;Get the Pinboard extension for Chrome&lt;/a&gt; or &lt;a href="https://addons.mozilla.org/en-US/firefox/addon/add-to-pinboard/"&gt;for Firefox&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Progressive Web Apps
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://pinboard-pwa.glitch.me/"&gt;Share-to-Pinboard Progressive Web App&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;I built my first progressive web app this year, once again writing code to facilitate my use of Pinboard. Progressive web apps are websites that can do special things on mobile. When you add this Pinboard PWA to your home screen on Android (you'll see a prompt to do so when visiting the site on a mobile browser), it adds an option to the native share menu (those options you see when you go to share a tweet or a web page) that makes it easy to add something to your collection of bookmarks on Pinboard.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tools
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://airtable-newsletter-cms.glitch.me/"&gt;Airtable as a Newsletter CMS&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;This is one of the most useful things I built this year - an app that, in conjunction with Airtable, functions as a CMS for &lt;a href="https://tinyletter.com/cassey"&gt;my housing &amp;amp; streets policy newsletter&lt;/a&gt;. I &lt;a href="https://dev.to/casseylottman/building-a-mini-cms-with-node-handlebars-and-airtable-128p"&gt;wrote about the app more extensively already&lt;/a&gt;, but basically, it uses the Airtable API to pull in records marked as 'Next Newsletter' in a specified base, and passes those records as data to a Handlebars template that outputs HTML I can paste into TinyLetter, so every newsletter is sent with a consistent format.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://copy-spotify-playlist.glitch.me/"&gt;Duplicate a Spotify Playlist&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;In September, I was listening to the Spotify playlist of Lizzo songs curated by Lizzo (or someone on Lizzo's staff at least) all the time, but some new remixes of a few songs were added, and I didn't enjoy them as much. I liked all the other songs on the playlist, though, and copying them over one-by-one sounded tedious. So, I built a little utility app where you can log in with your Spotify account, enter a playlist name and the identifier of a playlist you want to copy, and the app will create a new playlist on your account with all the same songs as the playlist you copied. Then, you can go into Spotify and add/remove songs at will.&lt;/p&gt;

&lt;p&gt;When I was first learning to code I kept seeing advice like "write code that solves a problem you have!" but I could never think of any problems I had that had a code-able solution. While I don't encounter problems like this every day, I do have a running backlog of app ideas now.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://tweet-thread-show.glitch.me/"&gt;Threaded Tweet Viewer&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Initially intended to be used on threads of tweets full of cartoons and memes, this app shows a thread one panel at a time using the Twitter API. I finished it on March 26, 2019.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://lnk-dates.glitch.me/"&gt;Date Night Idea Generator&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;I found a bunch of good uses for AirTable this year. For example, I created a base and filled it full of things I might plausibly want to do on a date in or around Lincoln, along with some metadata like if it involves being outdoors and what category of date I'd consider it. Then I made this little app to display a random record from that base from a given category. Work on this app happened between July 19 and July 22 of 2019.&lt;/p&gt;

&lt;h2&gt;
  
  
  Just for Fun
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://tally-cat.glitch.me/"&gt;Tally Cat&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;I finished a website for Tally, so she can have one just like her brother &lt;a href="https://soulpatch.glitch.me"&gt;Soul Patch&lt;/a&gt;!&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://best-friend-liz.glitch.me/"&gt;My Best Friend Liz&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;This app was easy - I remixed an app another user (and later, Glitch team member!) created that &lt;a href="http://celebrate.glitch.me/"&gt;displays a random grid of gifs alongside some text&lt;/a&gt;. I just needed a few modifications to the gif search terms and some different text options, and I had a site! I did end up adding a bit more customization though, so that I could source my "facts" about Elizabeth Warren from the Twitter user who initially made the claim.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://dearlisathegreat.glitch.me/"&gt;A Neopets PetPage I Created Around 2005&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Okay, I didn't really write this code this year - but I did, at long last, manage to log in to my old Neopets account, so I could find out the name of one of my pets and see the petpage I created sometime around 2005. I encountered code for the first time on Neopets.com - the virtual pet world allowed users to create a static site for each pet, and even had comprehensive text-based lessons on HTML for users like me to learn from. You can't see my original pet page unless you're logged in to Neopets.com - so I grabbed the HTML while logged in and brought it into the light. I think this probalby wasn't the only site I had, just the final iteration of the one that survived until now.&lt;/p&gt;

&lt;p&gt;This post initially appeared &lt;a href="https://www.cassey.dev/posts/2020-01-02-last-year-in-code/"&gt;on my personal site&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>2019</category>
      <category>yearinreview</category>
      <category>glitch</category>
    </item>
    <item>
      <title>Building a Mini CMS with Node, Handlebars, and Airtable</title>
      <dc:creator>Cassey Lottman</dc:creator>
      <pubDate>Fri, 05 Jul 2019 20:23:43 +0000</pubDate>
      <link>https://forem.com/casseylottman/building-a-mini-cms-with-node-handlebars-and-airtable-128p</link>
      <guid>https://forem.com/casseylottman/building-a-mini-cms-with-node-handlebars-and-airtable-128p</guid>
      <description>&lt;p&gt;I recently started &lt;a href="https://tinyletter.com/cassey" rel="noopener noreferrer"&gt;a newsletter on housing &amp;amp; streets policies using TinyLetter.com&lt;/a&gt;. For my first couple editions, I used TinyLetter's WYSIWYG editor, but I found before long that &lt;a href="https://tinyletter.com/cassey/letters/america-the-update" rel="noopener noreferrer"&gt;the HTML &amp;amp; styling it generates can be very inconsistent&lt;/a&gt;. How embarrassing! &lt;/p&gt;

&lt;p&gt;Fortunately, the TinyLetter WYSIWYG editor also lets you enter HTML source directly. I decided that would be the best route, but I'd prefer to write my newsletters in Markdown and generate the HTML in a structured way. I also was looking for a way to enter ideas for my newsletter on the go - the TinyLetter editor on mobile isn't the most friendly, and I don't have a go-to notes app that I use already. &lt;/p&gt;

&lt;p&gt;I came across &lt;a href="https://changelog.com/posts/trello-as-a-cms" rel="noopener noreferrer"&gt;this blog post on using Trello as a CMS&lt;/a&gt; and decided to try to build something similar using &lt;a href="https://airtable.com" rel="noopener noreferrer"&gt;Airtable&lt;/a&gt;, which I already use for storing structured personal data and to-do lists. I knew that there are some &lt;a href="https://glitch.com/@cassey/airtable-examples-starters" rel="noopener noreferrer"&gt;great Airtable starter projects to remix on Glitch.com&lt;/a&gt;, so building off one of those felt like a natural step. I remixed &lt;a href="https://glitch.com/~airtable-example" rel="noopener noreferrer"&gt;the Glitch project Airtable-Example&lt;/a&gt; and began hacking. &lt;/p&gt;

&lt;p&gt;First, I built the &lt;a href="https://airtable.com/shrCO5ikWX59JShpn" rel="noopener noreferrer"&gt;Airtable base to hold my newsletter content&lt;/a&gt;. My newsletter is typically in the form of a link roundup, so I expect each newsletter to have multiple entries with a title and associated URL, and a description that tells why I think people might find this link interesting. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxye67enlbgm7j2mojxxr.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxye67enlbgm7j2mojxxr.PNG" alt="The Kanban view of the Airtable base where I store my newsletter content ideas" width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, I started working on the code. At first I thought maybe I'd want to write the generated HTML to a file that I could copy, but I also wanted to be able to see the rendered HTML of a given newsletter before pasting it in to the TinyLetter editor. So, I decided on a format where the HTML will be displayed side-by-side with the rendered newsletter contents. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbyh1m7ye2imu5flpiaw8.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbyh1m7ye2imu5flpiaw8.PNG" alt="The view I want for my newsletter: raw HTML I can easily copy on one side, with the rendered version of that HTML on the other side" width="800" height="265"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At first I was using EJS, as it's a templating engine that has worked well for me on simple projects in the past. I soon found some limitations though that led to a switch to Handlebars. Primarily, there is no support for custom filters in the latest major version of EJS. I wanted a filter to render some of my data (the description field of each newsletter item) as markdown, so that I could have nicely formatted descriptions when I had a lot to say about a given link.&lt;/p&gt;

&lt;p&gt;The case where I had a lot to say about one particular link also led to a new format for my newsletter: instead of an &lt;code&gt;&amp;lt;ul&amp;gt;&lt;/code&gt; with many links, I wanted to send out info about just a single link, which wouldn't belong in a &lt;code&gt;&amp;lt;ul&amp;gt;&lt;/code&gt;. So, I found some helper code for a &lt;code&gt;compare&lt;/code&gt; filter in Handlebars that would let me render a &lt;code&gt;&amp;lt;ul&amp;gt;&lt;/code&gt; if I have multiple links to show, and a &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; if there is just one link. I found it a bit odd that this isn't built in to Handlebars, but it was easy enough to add a custom helper for it. &lt;/p&gt;

&lt;p&gt;I wanted my work-in-progress newsletters to be private, so I added some very basic authentication. I created a form on the index page with a password field, which has to be filled in to match the value I set in &lt;code&gt;.env&lt;/code&gt; in order to reveal the contents of the newsletter.  &lt;/p&gt;

&lt;p&gt;I also wanted my newsletter CMS to be as generalized as possible so others who found it useful could use it. So, I stored all the info that's custom to my app (the name of my newsletter, my name, the values to configure the base to pull newsletter contents from, etc.) in the &lt;code&gt;.env&lt;/code&gt; file. When you &lt;a href="https://glitch.com/edit/#!/remix/airtable-newsletter-cms" rel="noopener noreferrer"&gt;remix the Airtable-Newsletter-CMS project on Glitch&lt;/a&gt;, you'll get a version of the project with the &lt;code&gt;.env&lt;/code&gt; ready to fill in with your own values. &lt;/p&gt;

&lt;p&gt;You can see &lt;a href="https://airtable-newsletter-cms.glitch.me" rel="noopener noreferrer"&gt;the running project on Glitch&lt;/a&gt; and remix it for your own use if this is something that feels useful to you.&lt;br&gt;
&lt;/p&gt;
&lt;div class="glitch-embed-wrap"&gt;
  &lt;iframe src="https://glitch.com/embed/#!/embed/airtable-newsletter-cms?path=index.html" alt="airtable-newsletter-cms on glitch"&gt;&lt;/iframe&gt;
&lt;/div&gt;
 

&lt;p&gt;And of course, if you care about housing &amp;amp; streets policy developments, &lt;a href="https://tinyletter.com/cassey" rel="noopener noreferrer"&gt;subscribe to Cassey's Livable Communities Roundup&lt;/a&gt;, which was the main impetus for creating this app.&lt;/p&gt;

</description>
      <category>glitch</category>
      <category>cms</category>
      <category>airtable</category>
      <category>tinyletter</category>
    </item>
    <item>
      <title>Why I Became a Community Health Engineer</title>
      <dc:creator>Cassey Lottman</dc:creator>
      <pubDate>Wed, 03 Apr 2019 22:28:12 +0000</pubDate>
      <link>https://forem.com/casseylottman/why-i-became-a-community-health-engineer-ph0</link>
      <guid>https://forem.com/casseylottman/why-i-became-a-community-health-engineer-ph0</guid>
      <description>&lt;p&gt;I recently transitioned from a general software engineering position to become a "Community Health Engineer" at &lt;a href="https://glitch.com"&gt;Glitch&lt;/a&gt;. That job title means I use software engineering to make sure that Glitch stays a safe and welcoming place to create and discover the app of your dreams. &lt;/p&gt;

&lt;p&gt;I wasn't initially looking for a community role when I found the job posting, but I discovered it was a perfect fit. &lt;/p&gt;

&lt;p&gt;Here's an excerpt from the job posting: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We’re looking for an experienced and community-focused front-end web developer to join our team and help us build the features on Glitch that will help keep it the friendliest community of coders ever!&lt;/p&gt;

&lt;p&gt;Our Community Health Engineer will work with the rest of the team to brainstorm, prototype and implement community health features on Glitch, like reporting abuse or displaying safe search results. This role requires both technical skills and the ability to communicate with the Glitch community.&lt;/p&gt;

&lt;p&gt;We want someone who will be actively thinking about the effects of our design and features on the community as we grow, and can interact with the community to make sure we’re doing it right.&lt;/p&gt;

&lt;p&gt;We’re looking for people with these technical skills:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Strong skills in client-side JavaScript, but you’re okay with diving into Node.js&lt;/li&gt;
&lt;li&gt;An ability to stay up-to-date on modern additions to the language (like ES7 features)&lt;/li&gt;
&lt;li&gt;Experience in building a11y-compliant interfaces right from the start&lt;/li&gt;
&lt;li&gt;Proficiency in component-based development (Glitch uses React!)&lt;/li&gt;
&lt;li&gt;Understanding of and experience in using APIs, both internal and 3rd party&lt;/li&gt;
&lt;li&gt;CSS savvy, meaning that you know when to use border vs. padding vs. margin, flexbox vs. tables vs. floats, and responsive, fluid design&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We’d be particularly delighted to hire someone with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User interface (UI) and user experience (UX) skills – enough to better collaborate with the designers on our team to make sure our health features are inclusive and relevant to our community health goals.&lt;/li&gt;
&lt;li&gt;Experience and/or interest in speaking at technical conferences – so we can communicate our work to the tech community and be a model for others in a similar space.&lt;/li&gt;
&lt;li&gt;A passion for online communities and an understanding of the interplay between interfaces and human interactions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The interpersonal skills will be crucial to your success in this role:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Effective, responsive and frequent multi-platform communication to make sure we hear and deliver on the needs of the Glitch community&lt;/li&gt;
&lt;li&gt;Ability to translate, communicate, and prioritize the needs and desires of the community with the needs and desires of the organization.&lt;/li&gt;
&lt;li&gt;Enthusiasm for our inclusion goals and an ability to help us measure and promote our progress in working towards them.&lt;/li&gt;
&lt;li&gt;Willingness to help us create a roadmap for creating and maintaining a best-in-class healthy community as we grow and evolve.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most importantly, we’re looking for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;People who care deeply about empowering everyone to create on the web, and who are thoughtful about how to serve a broad set of audiences with sometimes conflicting community goals.&lt;/li&gt;
&lt;li&gt;Fluency and familiarity with issues around multiple facets of accessibility and healthy communities.&lt;/li&gt;
&lt;li&gt;Comfort with creating in collaboration, both with colleagues on our team and with members of the Glitch community. Ability to both handle projects and effectively delegate projects.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;As part of the application, I was asked to describe what community means to me, and what kind of roles I've had in communities in the past. My answer was long and heartfelt, touching on topics ranging from what it meant to be a member of the rural community where I grew up, to finding solace in a subreddit focused on a health condition I experienced, to organizing a grassroots movement for safer streets in my neighborhood with people I'd just met.&lt;/p&gt;

&lt;p&gt;In the role I held before starting my current job, I had been an active user and community member before being hired as a software engineer. Once on staff, while my insights as a former active user were highly valued, I also wanted to continue engaging with the community as I had done before. That engagement felt important, but it wasn't factored in to my weekly story points or my team's expectations for how I was spending my time. I felt a lot of frustration in that tension - by engaging with the community, I was discovering bugs and pain points, getting a lot of feedback, and learning about how others used the product. I wasn't on the team that was formally charged with managing the community, so I also ran into friction when my ideas for how to engage with users differed from the official moderators' opinions. Sometimes I found harsh negative feedback from the community that I felt should be shared with the wider staff, but when I did, it was interpreted as a personal attack coming straight from me.&lt;/p&gt;

&lt;p&gt;While that experience was challenging and often frustrating, it turned out to be valuable in my application to be a Community Health Engineer. It also helped that I've been reading and engaging in discussion for years on topics like inclusion, accessibility, and the culture of the web. &lt;/p&gt;

&lt;p&gt;So far, I'm really happy in my role as a Community Health Engineer. I get to spec out new features and write code, and also engage with a passionate, creative community who surprise and delight me every day. I also feel safe fighting for accessibility and proactively pointing out ways our software could be used for harm, because it's literally in my job description. &lt;/p&gt;

</description>
      <category>career</category>
      <category>community</category>
      <category>glitch</category>
      <category>devrel</category>
    </item>
    <item>
      <title>Nevertheless, Cassey Lottman Coded (and more)</title>
      <dc:creator>Cassey Lottman</dc:creator>
      <pubDate>Fri, 08 Mar 2019 20:18:25 +0000</pubDate>
      <link>https://forem.com/casseylottman/nevertheless-cassey-lottman-has-a-life-outside-code-96n</link>
      <guid>https://forem.com/casseylottman/nevertheless-cassey-lottman-has-a-life-outside-code-96n</guid>
      <description>&lt;p&gt;I'm a web developer, but first and foremost, I'm a community member. My communities include women-in-tech-on-Twitter, progressives fighting for change in a red state, &lt;a href="https://www.reddit.com/r/weddingplanning" rel="noopener noreferrer"&gt;r/weddingplanning&lt;/a&gt;, &lt;a href="//facebook.com/RentersTogetherLNK/"&gt;advocates for renters' rights and affordable housing&lt;/a&gt;, my book club, people making cool stuff on &lt;a href="https://www.glitch.com" rel="noopener noreferrer"&gt;Glitch&lt;/a&gt;, and so many more. My communities are what drive me - coding is my job but not my life, even though some of those community memberships only make sense &lt;em&gt;because&lt;/em&gt; I code.&lt;/p&gt;

&lt;h2&gt;
  
  
  I continued to code in 2019 because...
&lt;/h2&gt;

&lt;p&gt;I need that $$$ to pay my mortgage. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/5fBH6z8aMV1RbA4FaSc/200w_d.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/5fBH6z8aMV1RbA4FaSc/200w_d.gif" alt="Woman getting rained on by dollar bills"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But also, because I am so excited about my new role &lt;a href="https://www.glitch.com" rel="noopener noreferrer"&gt;@glitch&lt;/a&gt; as a Community Health Engineer. My job is to build the tools to make sure that as Glitch grows, we don't become the kind of hellscape for minorities that other big social networks have turned into. The job combines my skills in Javascript and React with my passion for building inclusive community spaces both in person and on the web. &lt;/p&gt;

&lt;h2&gt;
  
  
  I deserve credit for...
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Attempting to &lt;a href="http://casseyforcouncil.com" rel="noopener noreferrer"&gt;run for public office&lt;/a&gt; while maintaining a full-time job and a healthy home life. My goal is to advance the conversation in local politics to include more people whose voices have been ignored, and prioritize the needs of those who are facing the greatest challenges. &lt;/li&gt;
&lt;li&gt;Some big projects I shipped in 2018 at my last job, especially around major speed improvements to our PHPUnit test suite.&lt;/li&gt;
&lt;li&gt;All the &lt;a href="https://glitch.com/@cassey/my-preciouses" rel="noopener noreferrer"&gt;silly side projects I've made this year&lt;/a&gt; in Javascript. It's been so long since I've coded for fun, and being surrounded by the amazing creativity of people building on Glitch has inspired me to join in. &lt;/li&gt;
&lt;/ul&gt;


&lt;div class="glitch-embed-wrap"&gt;
  &lt;iframe src="https://glitch.com/embed/#!/embed/soulpatch?previewSize=100&amp;amp;path=index.html" alt="soulpatch on glitch"&gt;&lt;/iframe&gt;
&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Trying out a new skill - pixel art! I made this truly horrendous turtle, but I know with practice I can get better. &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fqg0r9kxhr1prsokhgoq7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fqg0r9kxhr1prsokhgoq7.png" alt="a really bad pixel art drawing of a turtle, with a pixelated caption reading 'turt'"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Fighting to make accessibility a first-class concern on every product I'm involved with, and training coworkers on semantic HTML and testing with Voiceover. I even made this app to help fellow devs practice their screenreader skills. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="glitch-embed-wrap"&gt;
  &lt;iframe src="https://glitch.com/embed/#!/embed/screenreader-practice?previewSize=100&amp;amp;path=index.html" alt="screenreader-practice on glitch"&gt;&lt;/iframe&gt;
&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Helping organize my neighbors &lt;a href="https://journalstar.com/news/local/th-street-makeover-coming-soon/article_ccfb6a29-194e-557f-93e3-72fab4b18f40.html" rel="noopener noreferrer"&gt;to fight for (and win!) increased safety on a major street through our neighborhood&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  I hope to see my tech community...
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Build accessibility into product design from the beginning of every iteration.&lt;/li&gt;
&lt;li&gt;Promote more women into leadership roles and give them authority to foster healthy teams.&lt;/li&gt;
&lt;li&gt;Reckon with the ethics of every piece of software we write.&lt;/li&gt;
&lt;li&gt;Teach our families how to use password managers, switch to encrypted messaging systems, and protect their personal info. (Including DNA!)&lt;/li&gt;
&lt;li&gt;Run for office and support candidates who are working to make the world a more inclusive place for all. (Not sure how? @ me!) &lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>wecoded</category>
    </item>
  </channel>
</rss>
