<?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>DEV Community: Jen Weber</title>
    <description>The latest articles on DEV Community by Jen Weber (@jenweber).</description>
    <link>https://dev.to/jenweber</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%2F56611%2Ff1b32681-cafe-463b-81b7-b258b3676b9f.jpeg</url>
      <title>DEV Community: Jen Weber</title>
      <link>https://dev.to/jenweber</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jenweber"/>
    <language>en</language>
    <item>
      <title>Remodeling an Ember App - Codemods and jQuery</title>
      <dc:creator>Jen Weber</dc:creator>
      <pubDate>Tue, 13 Jul 2021 21:33:37 +0000</pubDate>
      <link>https://dev.to/jenweber/remodeling-an-ember-app-codemods-and-jquery-3e8k</link>
      <guid>https://dev.to/jenweber/remodeling-an-ember-app-codemods-and-jquery-3e8k</guid>
      <description>&lt;p&gt;When you need to upgrade and ember app, codemods can help you update your app's syntax faster than you could make changes by hand. Today, we'll talk about codemods and cover what to do about jQuery usage in your apps.&lt;/p&gt;

&lt;p&gt;This is Part 4 of a series of blog posts. We're on a journey together to remodel an older Ember app, &lt;a href="https://github.com/ember-learn/ember-api-docs"&gt;ember-api-docs&lt;/a&gt;, incrementally bringing it up to date with the latest and best Ember and Ember Data patterns.&lt;/p&gt;

&lt;p&gt;For this series, I'm pair programming with Chris Thoburn, aka &lt;a href="https://github.com/runspired"&gt;@runspired&lt;/a&gt;, who is known for&lt;br&gt;
his work on Ember Data. He has over 500 commits and some great&lt;br&gt;
debugging skills that you and I can learn from.&lt;/p&gt;
&lt;h2&gt;
  
  
  What you will learn in this segment
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;How to find codemods&lt;/li&gt;
&lt;li&gt;How to run the codemods&lt;/li&gt;
&lt;li&gt;How to decide what to change, and what to leave alone&lt;/li&gt;
&lt;li&gt;Where jQuery fits into the story&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  The road so far
&lt;/h2&gt;

&lt;p&gt;So far, we have upgraded our dependencies and tests are all passing. This sets a strong foundation for running codemods and then making sure that tests keep passing.&lt;/p&gt;
&lt;h2&gt;
  
  
  Octanify
&lt;/h2&gt;

&lt;p&gt;Ember Octane is Ember's first "edition." You can think of an edition as a collection of features and syntax that together form a cohesive mental model. There are multiple ways to accomplish a feature in Ember, and Octaneified apps use the latest styles.&lt;/p&gt;

&lt;p&gt;There is a CLI command that configures an app to use Octane:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx @ember/octanify from   which set some dependencies and flipped flags in optional-features.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can find more instructions about this command in the &lt;a href="https://guides.emberjs.com/release/upgrading/current-edition/"&gt;Ember upgrade guide&lt;/a&gt;. In short, it sets some dependencies in &lt;code&gt;package.json&lt;/code&gt; and feature flags in &lt;code&gt;optional-features.json&lt;/code&gt;. Optional features are one way that new features are rolled out in Ember apps without making breaking changes. When you are ready, you can opt into them, but if you are not ready, you aren't blocked from upgrading. Regular upgrading is critical for companies and teams that value getting security, bugfixes, and feature updates over long periods of time.&lt;/p&gt;

&lt;p&gt;Octanify sets the following feature flags in &lt;code&gt;optional-features.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "default-async-observers": true,
  "jquery-integration": false,
  "template-only-glimmer-components": true,
  "application-template-wrapper": false,
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can learn all about these individual features in the &lt;a href="https://guides.emberjs.com/release/configuring-ember/optional-features/"&gt;Optional Features Guide&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Handling jQuery
&lt;/h2&gt;

&lt;p&gt;For our app, all the optional features set by Octanify were fine. Setting &lt;code&gt;jquery-integration: false&lt;/code&gt; meant that instead of using &lt;code&gt;this.$()&lt;/code&gt; in our apps, we had to install &lt;code&gt;@ember/jquery&lt;/code&gt; and import jQuery individually - no problem. However, the &lt;code&gt;jquery-integration&lt;/code&gt; flag made us wonder, could we remove &lt;code&gt;jQuery&lt;/code&gt; from our app altogether? We were only using it in one place in our app, and doing so would cut some kb from our app.&lt;/p&gt;

&lt;p&gt;However, we didn't just need to check our app. We also had to check if any addons used jQuery. I used to search my &lt;code&gt;node_modules&lt;/code&gt; for usages, but that would return a lot of false positives compared to a strategy that Chris Thoburn showed me.&lt;/p&gt;

&lt;p&gt;Chris first ran the build for the app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx ember build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By default, the command puts built files in the &lt;code&gt;dist/&lt;/code&gt; directory. Then, Chris was able to search for &lt;code&gt;this.$&lt;/code&gt; and &lt;code&gt;Ember.$&lt;/code&gt; and confirm that our app's addons did not need jQuery. This is better than searching &lt;code&gt;node_modules&lt;/code&gt;, since we are only checking for the use of jQuery in addon features we are &lt;em&gt;actually using&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Another common use of jQuery in apps is via Ember Data. By default, Ember Data uses jQuery for its HTTP requests. However, if an app has &lt;code&gt;ember-fetch&lt;/code&gt; installed, it will use &lt;code&gt;fetch&lt;/code&gt; instead. It's important to install &lt;code&gt;ember-fetch&lt;/code&gt; in order to provide broad browser support for your fetch requests.&lt;/p&gt;

&lt;p&gt;Finally, we took another look at our direct use of jQuery in this app, in our Table of Contents component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@ember/object&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@ember/component&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;jQuery&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;jquery&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;TableOfContents&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;action&lt;/span&gt;
  &lt;span class="nx"&gt;toggle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;jQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ol.toc-level-1.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slideToggle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;jQuery is providing a nice open/close animation for one of our menus. Whenever I see jQuery in use, I always check &lt;a href="http://youmightnotneedjquery.com/"&gt;youmightnotneedjquery&lt;/a&gt; to see if there's an easy alternative. In this case, there was not, so in the interest of moving forward, we leave jQuery in our app for now, and open an issue asking for help making a new CSS/plain JavaScript animation.&lt;/p&gt;

&lt;p&gt;It's not a huge deal to leave jQuery in your app unless you have a strategic, benchmarked focus on app performance. jQuery is an incredibly successful project - so successful that its best features are now provided by native browser JavaScript. Ember's API documentation app is used by developers around the world with varying internet quality levels, and so we do need to save some kb where we can, however this one task should not block our progress towards improving other areas of the app.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ember CLI Update Codemods
&lt;/h2&gt;

&lt;p&gt;Now on to some more codemods. &lt;a href="https://github.com/ember-cli/ember-cli-update"&gt;Ember CLI Update&lt;/a&gt; can update your dependencies, and also provides a subset of the most common codemods that make deeper changes.&lt;/p&gt;

&lt;p&gt;After running dependency updates, you can run the codemods like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Start your app&lt;/span&gt;
npx ember serve
&lt;span class="c"&gt;# Run the codemods&lt;/span&gt;
npx ember-cli-update &lt;span class="nt"&gt;--run-codemods&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Some codemods start with the letters &lt;code&gt;fpe&lt;/code&gt;. This stands for "function prototype extension."&lt;/p&gt;

&lt;h2&gt;
  
  
  Additional codemods
&lt;/h2&gt;

&lt;p&gt;There are many more codemods than those provided by Ember CLI update. One good place to look for them is &lt;a href="https://github.com/ember-codemods"&gt;ember-codemods&lt;/a&gt; on GitHub.&lt;/p&gt;

&lt;p&gt;Some codemods require that you have your app running. That's why we start the app with &lt;code&gt;ember serve&lt;/code&gt;. Such codemods look at the built files in order to infer the correct changes to make. This is possible through a strategy called telemetry, via &lt;a href="https://github.com/ember-codemods/ember-codemods-telemetry-helpers"&gt;&lt;code&gt;ember-codemods-telemetry-helpers&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  A problem with one codemod
&lt;/h3&gt;

&lt;p&gt;When we ran &lt;code&gt;ember-modules-codemod&lt;/code&gt;, we encountered an error. The codemod helpfully told us which line it failed on:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;titleToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This line of code uses optional chaining, with &lt;code&gt;?.&lt;/code&gt; syntax. Optional chaining is a feature of JavaScript that was added &lt;em&gt;after&lt;/em&gt; these codemods were initially written.&lt;/p&gt;

&lt;p&gt;We can see for ourselves one of the challenges of codemods - when they are written, they are a snapshot in time. It takes work to keep them functioning as JavaScript and Ember apps change. If you are working on a large app, it may be less work to fix a codemod bug than to make all the changes by hand. Additionally, codemods are written to work for individuals' apps, and so it takes community effort for codemods to work across many edge cases that authors could not forsee.&lt;/p&gt;

&lt;p&gt;Another example of maintainability issues with codemods is the ES5 getter codemod - you have to run it before you run native classes codemods, because it doesn't know how to parse native classes. They didn't exist when the getter codemod was written. These aren't unsolvable problems, but they mean that developers whose apps are super out of date may have a harder time upgrading. There are many benefits to having a regular ugrade and maintenance schedule for your work, and this is one example.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuring VSCode to play nice with decorators
&lt;/h2&gt;

&lt;p&gt;Some of the codemods we ran introduced decorators. VSCode was our code editor of choice, and its default linters didn't like the use of decorators.&lt;/p&gt;

&lt;p&gt;We removed &lt;code&gt;jsconfig.json&lt;/code&gt; from our app's &lt;code&gt;.gitignore&lt;/code&gt;, and then configured VSCode to stop yelling about decorators in &lt;code&gt;jsconfig.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "compilerOptions": {
      "experimentalDecorators": true
    },
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Dealing with codemod mistakes
&lt;/h2&gt;

&lt;p&gt;Not all codemods are flawless. There's a lot of variation in an app! You should think of them has helpful suggestions, rather than a complete solution to your upgrade process. The best way to catch codemod mistakes is to carefully review the diff, run your tests, and make a commit after each codemod. Here's an example issue we had with a codemod that rewrote &lt;code&gt;link-to&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight handlebars"&gt;&lt;code&gt;// before codemod

&lt;span class="k"&gt;{{#&lt;/span&gt;&lt;span class="nn"&gt;link-to&lt;/span&gt;
  &lt;span class="nv"&gt;data-test-uses-link&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;concat&lt;/span&gt; &lt;span class="nv"&gt;parentName&lt;/span&gt; &lt;span class="nv"&gt;section&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;routeSuffix&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nv"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;id&lt;/span&gt;
    &lt;span class="nv"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;projectVersion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;compactVersion&lt;/span&gt;
    &lt;span class="nv"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;
    &lt;span class="nv"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;query-params&lt;/span&gt; &lt;span class="nv"&gt;anchor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="k"&gt;}}&lt;/span&gt;
  &lt;span class="k"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="k"&gt;}}&lt;/span&gt;
&lt;span class="k"&gt;{{/&lt;/span&gt;&lt;span class="nn"&gt;link-to&lt;/span&gt;&lt;span class="k"&gt;}}&lt;/span&gt;

// after codemod
&lt;span class="nt"&gt;&amp;lt;LinkTo&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="na"&gt;route=&lt;/span&gt;&lt;span class="k"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt;concat&lt;/span&gt; &lt;span class="nv"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;parentName&lt;/span&gt; &lt;span class="nv"&gt;section&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;routeSuffix&lt;/span&gt; &lt;span class="k"&gt;}}&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="na"&gt;models=&lt;/span&gt;&lt;span class="k"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt;array&lt;/span&gt; &lt;span class="nv"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;id&lt;/span&gt; &lt;span class="nv"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;projectVersion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;compactVersion&lt;/span&gt;&lt;span class="k"&gt;}}&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="na"&gt;query=&lt;/span&gt;&lt;span class="k"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt;hash&lt;/span&gt; &lt;span class="nv"&gt;anchor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="k"&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;The codemod cut out some of our route segments, leading to incorrect links in one part of the app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// correct
/ember-data/3.26/classes/Ember.Inflector/methods/singular?anchor=singular

// incorrect
/ember-data/3.26/classes/ember-data/methods/3.26?anchor=singular
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;How did this happen? We took a look at the source code for the codemod, and saw that it has special handling for dynamic routes, query params, and data-test. When we used all three of these things together in one link-to, it was the perfect storm.&lt;/p&gt;

&lt;h2&gt;
  
  
  Codemod strategies and takeaways
&lt;/h2&gt;

&lt;p&gt;Our upgrade would have been easier if we ran a single codemod at a time, and make it its own commit, and ran it in CI, and shipped it. If you have the ability to roll your app back quickly in production, you don't need to work as carefully.&lt;/p&gt;

&lt;p&gt;That said, you really need to go through the diff if you try to do a big bang upgrade.&lt;/p&gt;

&lt;p&gt;If your test suite coverage is bad, and you can't improve it, you can run codemods on specific chunks of code and QA them - do one set of related components at a time, then look at the diff and click test. Many (or maybe all) codemods accept file paths in the CLI commands.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;That's it for codemods! Next up, we will take a look at the code that couldn't be modded, and do some refactors to simplify the app now that we have Octane's awesome features available, such as &lt;code&gt;tracked&lt;/code&gt;. Thanks for reading!&lt;/p&gt;

</description>
      <category>ember</category>
    </item>
    <item>
      <title>Remodeling an Ember App - Testing</title>
      <dc:creator>Jen Weber</dc:creator>
      <pubDate>Thu, 17 Jun 2021 02:41:01 +0000</pubDate>
      <link>https://dev.to/jenweber/remodeling-an-ember-app-testing-115h</link>
      <guid>https://dev.to/jenweber/remodeling-an-ember-app-testing-115h</guid>
      <description>&lt;p&gt;Today's topic is debugging an Ember app's test suite after upgrading some dependencies. This is a real-world app and the issues we face will be different from your apps, but you can learn the overall strategy and debugging approaches,&lt;/p&gt;

&lt;p&gt;This is Part 3 of a series of blog posts. We're on a journey together to remodel an older Ember app, &lt;a href="https://github.com/ember-learn/ember-api-docs"&gt;ember-api-docs&lt;/a&gt;, incrementally bringing it up to date with the latest and best Ember and Ember Data patterns.&lt;/p&gt;

&lt;p&gt;For this series, I'm pair programming with Chris Thoburn, aka &lt;a href="https://github.com/runspired"&gt;@runspired&lt;/a&gt;, who is known for his work on Ember Data. He has over 500 commits and some great debugging skills that you and I can learn from.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you will learn in this segment
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;How to run tests on-demand instead of on every change&lt;/li&gt;
&lt;li&gt;How to run the tests for different git branches, side by side&lt;/li&gt;
&lt;li&gt;What to expect in your test suite after upgrading the linters&lt;/li&gt;
&lt;li&gt;How to deal strategically and efficiently with hundreds of linting errors&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Our progress so far
&lt;/h2&gt;

&lt;p&gt;In the previous article, we had updated a bunch of dependencies and solved issues that prevented the app from building (build time errors) or prevented it from working correctly in the browser (runtime errors). We got to the end successfully, but there were some test failures.&lt;/p&gt;

&lt;p&gt;Why were there failures? Well, we made a &lt;em&gt;lot&lt;/em&gt; of changes! No matter what framework I'm using, any time I make a bunch of changes before running my test suite, I expect some tests to fail. Another path we could have chosen was to make changes one at a time, while running the test suite at every step. However, sometimes, seasoned Ember.js developers can take a big leap forward and then reconcile the errors. Sometimes, this latter approach saves you time, but if you get stuck, it's a good idea to take a step back and do one change at a time.&lt;/p&gt;

&lt;h2&gt;
  
  
  New tools for your toolkit - test running modes
&lt;/h2&gt;

&lt;p&gt;Sometimes, the default behavior of &lt;code&gt;ember test --server&lt;/code&gt; gets in the way. By default, the app rebuilds and test run every time you make a change. That wipes out the test failure information that you may need to reference while you make changes in multiple files.&lt;/p&gt;

&lt;p&gt;Chris Thoburn showed me one way to improve on this experience and fix my test failures more quickly! He often runs a build continuously, and then in a separate process, run the tests. Although the app rebuilds every time you make a change, the test only re-run when you tell them to. So, the test failure output is always there when we need it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# In one tab of your terminal, start the build and watch for changes&lt;/span&gt;
ember build &lt;span class="nt"&gt;--watch&lt;/span&gt; &lt;span class="nt"&gt;--output-path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"./dist"&lt;/span&gt;

&lt;span class="c"&gt;# In a new tab or window of your terminal, run the tests&lt;/span&gt;
ember &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;--serve&lt;/span&gt; &lt;span class="nt"&gt;--path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"./dist"&lt;/span&gt; &lt;span class="nt"&gt;--no-launch&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In these examples, we pointed the tests to the &lt;code&gt;dist&lt;/code&gt; folder for the built app. We can apply this same strategy in order to run tests from different git branches side by side. For example, you could check out one branch of your app, run a single build, check out another branch, run a build, and then run the tests for both. Then you can inspect the results and compare them! You can even add debuggers to both branches and stop the test suites in the same place to inspect the state. Here's how!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git checkout main
yarn &lt;span class="nb"&gt;install
&lt;/span&gt;ember build &lt;span class="nt"&gt;--output-path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"./dist-main"&lt;/span&gt;
git checkout upgrade-branch
ember build &lt;span class="nt"&gt;--output-path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"./dist-my-upgrade-branch"&lt;/span&gt;
&lt;span class="c"&gt;# Run the tests for main&lt;/span&gt;
ember &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;--serve&lt;/span&gt; &lt;span class="nt"&gt;--path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"./dist-main"&lt;/span&gt; &lt;span class="nt"&gt;--no-launch&lt;/span&gt;
&lt;span class="c"&gt;# Run the tests for the upgrade branch&lt;/span&gt;
ember &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;--serve&lt;/span&gt; &lt;span class="nt"&gt;--path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"./dist-my-upgrade-branch"&lt;/span&gt; &lt;span class="nt"&gt;--no-launch&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Resolving linting errors
&lt;/h2&gt;

&lt;p&gt;One change we made was that we increased the version number of &lt;code&gt;eslint-plugin-ember&lt;/code&gt; and &lt;code&gt;ember-template-lint&lt;/code&gt;. When we did that, we brought in new linting rules for our &lt;code&gt;.hbs&lt;/code&gt; templates and JavaScript files. We got automatic guidance on how we could improve our app's syntax, coding style, and most importantly, its accessibility. However, it means our linting tests were all failing with over 100 errors! How do we deal with that?&lt;/p&gt;

&lt;p&gt;For every linting error or warning, we must choose between the following options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Update the codebase itself to resolve the warning&lt;/li&gt;
&lt;li&gt;Turn the rule off in &lt;code&gt;.eslintric&lt;/code&gt; or &lt;code&gt;.template-lintrc.js&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Add a code comment that tells the linter to ignore that file or line of code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most of the time, when you are doing a dependencies upgrade, you should only fix very very tiny things and for everything else, ignore the rule and do the fixes themselves in later PRs. Why? We don't want to inadverdantly change the app's behavior! When upgrading dependencies, ideally the app looks the same when we're done.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tools to help you deal with linting errors
&lt;/h3&gt;

&lt;p&gt;There are some helpful tools in the Ember ecosystem for tracking and resolving linting issues over time, and they are especially important for large apps or teams.&lt;/p&gt;

&lt;p&gt;First, &lt;code&gt;ember-template-lint&lt;/code&gt; helps you automatically convert template linting errors into future to-do tasks. You can learn more about this feature in the &lt;a href="https://blog.emberjs.com/how-to-todo-in-ember-template-lint/"&gt;Official Ember Blog&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Second, Chris Manson created &lt;a href="https://github.com/mansona/lint-to-the-future"&gt;&lt;code&gt;lint-to-the-future&lt;/code&gt;&lt;/a&gt;, which turns all your errors into code comments that ignore the rule. When you fix a warning, remove the code comment. You can also visualize and measure your progress with some graphs!&lt;/p&gt;

&lt;h3&gt;
  
  
  Our approach
&lt;/h3&gt;

&lt;p&gt;Although 100+ linting errors sounds like a lot, most of them were the same error over and over again. We could see them by running &lt;code&gt;yarn lint&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We wanted to avoid making too many unnecessary changes in this app until after our upgrade step was over, so we turned a whole bunch of rules off in our &lt;code&gt;.eslintrc&lt;/code&gt;. It makes sense that we had to turn off these rules, since many of them were telling us about how to turn our app into an Octane-style app. They will be useful after we finish the dependencies upgrade! We can learn more about each rule by searching for the rule name in the &lt;a href="https://github.com/ember-cli/ember-cli-eslint"&gt;&lt;code&gt;ember-cli-eslint&lt;/code&gt;&lt;/a&gt; source code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// excerpt from .eslintrc&lt;/span&gt;
  &lt;span class="nx"&gt;rules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ember/no-jquery&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;off&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ember/no-jquery&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;off&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;no-console&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;off&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ember/no-new-mixins&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;off&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ember/no-mixins&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;off&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ember/native-classes&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;off&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ember/require-tagless-components&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;off&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ember/no-test-this-render&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;off&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ember/no-classic-classes&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;off&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ember/no-get&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;off&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ember/no-actions-hash&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;off&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ember/no-classic-components&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;off&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ember/no-private-routing-service&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;off&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We only needed to ignore two rules in our &lt;code&gt;.template-lintrc.js&lt;/code&gt;, we only needed to add two rule ignores. We can learn all about why these rules exist by searching for the rule name in &lt;a href="https://github.com/ember-cli/eslint-plugin-ember"&gt;&lt;code&gt;eslint-plugin-ember&lt;/code&gt; source code&lt;/a&gt;. The file name matches the rule that shows up in the warnings. You can find it quickly on GitHub by pressing the letter &lt;code&gt;T&lt;/code&gt; from the repository's main page and typing in the name of the rule.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// excerpt from .template-lintrc.js&lt;/span&gt;
&lt;span class="nx"&gt;rules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;no-link-to-positional-params&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;require-input-label&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="c1"&gt;// and some more rules that were already there&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://github.com/ember-template-lint/ember-template-lint/blob/master/docs/rule/require-input-label.md"&gt;&lt;code&gt;require-input-label&lt;/code&gt;&lt;/a&gt; is an example of a linting rule that helps you discover accessibility issues in your app! It warns you if you have an input element that lacks an associated label element. In our case, this warning was a false hit - we found a bug! We &lt;a href="https://github.com/ember-template-lint/ember-template-lint/issues/1835#issuecomment-857223622"&gt;reported the bug&lt;/a&gt; and linked to the public example of it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/ember-template-lint/ember-template-lint/blob/master/docs/rule/no-link-to-positional-params.md"&gt;&lt;code&gt;no-link-to-positional-params&lt;/code&gt;&lt;/a&gt; was telling us not to do links in this style: &lt;code&gt;{{link-to "About Us" "about"}}&lt;/code&gt;, Instead, we should do &lt;code&gt;&amp;lt;LinkTo @route="about"&amp;gt;About Us&amp;lt;/LinkTo&amp;gt;&lt;/code&gt;. We can definitely handle this later.&lt;/p&gt;

&lt;p&gt;Once our linting tests were passing, we moved on to the next step!&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding application test failures
&lt;/h2&gt;

&lt;p&gt;When you do an upgrade like this, there are some common sources of failures. It's helpful to ponder thus line of questioning below for a little when you run into a test that is tricky to fix:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Did I make a mistake during the upgrade?&lt;/li&gt;
&lt;li&gt;Did the upgrade uncover a bug that was hidden previously?&lt;/li&gt;
&lt;li&gt;Were there any breaking changes in my dependencies?&lt;/li&gt;
&lt;li&gt;Was my app relying on a bug in Ember that was fixed?&lt;/li&gt;
&lt;li&gt;Did my app rely on private API methods?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After pondering this list, now I can move to the next level:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What evidence do I have that my hypothesis is correct?&lt;/li&gt;
&lt;li&gt;Do I need to update a test, update something in my app, or both?&lt;/li&gt;
&lt;li&gt;If I reread the test failure again, do I get any new insights?&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Our test failures
&lt;/h3&gt;

&lt;p&gt;Here's an example test failure we worked through:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Error: Element not found when calling `fillIn('#ember-basic-dropdown-content-ember
1246 .ember-power-select-search-input[type=search]')`.
  at http://localhost:7357/assets/test-support.js:35450:15
  at async selectSearch (http://localhost:7357/assets/test-support.js:39374:9)
  at async Object.&amp;lt;anonymous&amp;gt; (http://localhost:7357/assets/tests.js:66:7)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case, the question that jumps out at us is "Were there any breaking changes in my dependencies?" We upgraded from &lt;code&gt;ember-power-select&lt;/code&gt; version &lt;code&gt;2.3.5&lt;/code&gt; to &lt;code&gt;4.1.6&lt;/code&gt;. Following the rules of semantic versioning, we can see that there have been two releases with breaking changes. Time to check the release notes of the library, in &lt;a href="https://github.com/cibernox/ember-power-select/blob/master/CHANGELOG.md"&gt;CHANGELOG.md&lt;/a&gt;. If you don't see a changelog for the library you are using, look at the Releases section on GitHub instead.&lt;/p&gt;

&lt;p&gt;By reading the changelog, we could see that there was a new required attribute to add to the component. Adding &lt;code&gt;@searchEnabled={{true}}&lt;/code&gt; to our power select dropdowns was all that was needed.&lt;/p&gt;

&lt;p&gt;Another test failure we saw was this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;not ok 66 Chrome 91.0 - [196 ms] - Acceptance | document title: is of format className - version - Ember API Docs
  ---
    actual: &amp;gt;
        Ember Api Docs
    expected: &amp;gt;
        Container - 1.0 - Ember API Documentation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This was an example of a mistake we made while upgrading. The test that was failing was checking the page title of a certain URL in the app. A page's title is important for SEO, accessibility, and overall user experience. It's part of the text that shows up in a search result. It is the text that shows up at the top of your browser tab. And for people who use assistive tech, it helps them know what page they are on when they flip through tabs. You can learn more about page titles in &lt;a href="https://guides.emberjs.com/release/accessibility/page-template-considerations/#toc_page-title"&gt;the Ember Guides&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;What happened was that when the upgrade diff was applied, it added something like &lt;code&gt;{{page-title "EmberApiDocs"}}&lt;/code&gt; to the &lt;code&gt;application.hbs&lt;/code&gt; template. Community member &lt;a href="https://github.com/prakashchoudhary07"&gt;prakashchoudhary07&lt;/a&gt; discovered that the page title was being set in another, more sophisticated way in this app. Therefore, we could delete the page title helper, and the test passed.&lt;/p&gt;

&lt;p&gt;Lastly, there was an error due to reliance on private API. One test was using private APIs on the router inside the test only. When I had tried to upgrade the test to use the router service instead, the method was no longer available. So, I undid the change I made during linting fixes and instead added an ignore to the &lt;code&gt;eslint.rc&lt;/code&gt;. We can deal with that issue in another PR!&lt;/p&gt;

&lt;h2&gt;
  
  
  Up next
&lt;/h2&gt;

&lt;p&gt;Now, all our tests are all passing! Next in this series, we will run some Octane codemods and refactor some components that are tough to work with. Thanks for reading!&lt;/p&gt;

</description>
      <category>ember</category>
    </item>
    <item>
      <title>Remodeling an Ember App - Package Updates</title>
      <dc:creator>Jen Weber</dc:creator>
      <pubDate>Wed, 09 Jun 2021 13:29:23 +0000</pubDate>
      <link>https://dev.to/jenweber/remodeling-an-ember-app-package-updates-22cg</link>
      <guid>https://dev.to/jenweber/remodeling-an-ember-app-package-updates-22cg</guid>
      <description>&lt;p&gt;Today's topic is upgrading dependencies on an older Ember app. This is a real-world app and the issues we face will be different from your apps, but you can learn the overall strategy and debugging approaches,&lt;/p&gt;

&lt;p&gt;This is Part 2 of a series of blog posts. We're on a journey together to remodel an older Ember app, incrementally bringing it up to date with the latest and best Ember and Ember Data patterns.&lt;/p&gt;

&lt;h2&gt;
  
  
  About the series
&lt;/h2&gt;

&lt;p&gt;We will walk through updating a complex, real-world app, &lt;a href="https://github.com/ember-learn/ember-api-docs"&gt;ember-api-docs&lt;/a&gt;, which is the front end of &lt;a href="https://api.emberjs.com"&gt;api.emberjs.com&lt;/a&gt;. Along the way, you will learn how to approach this process for your own apps - updating dependencies, debugging build errors, migrating to Octane syntax, writing better Ember Data serializers &amp;amp; adapters... there's a lot to do!&lt;/p&gt;

&lt;p&gt;For this series, I'm pair programming with Chris Thoburn, aka &lt;a href="https://github.com/runspired"&gt;@runspired&lt;/a&gt;, who is known for his work on Ember Data. He has over 500 commits and some great debugging skills that you and I can learn from.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deciding how to approach upgrading dependencies
&lt;/h2&gt;

&lt;p&gt;There are two main approaches Ember developers take, either:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Upgrade addons&lt;/li&gt;
&lt;li&gt;Upgrade core Ember and Ember Data dependencies&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Or, they approach this in the reverse order:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Upgrade core Ember and Ember Data dependencies&lt;/li&gt;
&lt;li&gt;Upgrade addons&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The path you choose depends on your app - how many addons does it have? How outdated are they?&lt;/p&gt;

&lt;p&gt;In our case, we decided on the latter. We didn't want to introduce too many changes at once if we didn't have to, and we were pretty confident in our ability to sort through addon-specific errors.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running the Ember and Ember Data upgrade
&lt;/h2&gt;

&lt;p&gt;This app was on 3.16. The latest Ember and Ember Data version is 3.26.&lt;/p&gt;

&lt;p&gt;We can do the upgrade with the help of &lt;code&gt;ember-cli-update&lt;/code&gt;, which will apply the blueprint used for fresh apps.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx ember-cli-update
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can read a whole bunch about upgrading in the &lt;a href="https://guides.emberjs.com/release/upgrading/"&gt;Ember Guides&lt;/a&gt; and &lt;a href="https://cli.emberjs.com/release/basic-use/upgrading/"&gt;Ember CLI Guides&lt;/a&gt;, so we won't go into too much detail here.&lt;/p&gt;

&lt;p&gt;We reviewed each file that was modified first, to confirm that we wanted those changes.&lt;/p&gt;

&lt;p&gt;Then, we walked through all merge conflicts and resolved them.&lt;/p&gt;

&lt;p&gt;Next, we installed our new dependencies with &lt;code&gt;yarn install&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Finally, we started the Ember server with &lt;code&gt;npx ember serve&lt;/code&gt; and hit our first bug.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(Why &lt;code&gt;npx ember serve&lt;/code&gt;? &lt;code&gt;npx&lt;/code&gt; ensures that the Ember CLI version used by your app is the one specified in package.json, and not your globally installed version. It usually doesn't matter, but when it does, it's often when working on upgrade tasks like this!)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Debugging a build failure
&lt;/h2&gt;

&lt;p&gt;Here's the build failure we saw in the console after we started up our server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Build Error (broccoli-persistent-filter:Babel &amp;gt; [Babel: @ember/ordered-set]) in @ember/ordered-set/index.js

Duplicate plugin/preset detected. If you'd like to use two separate instances of a plugin, they need separate names, e.g.

  plugins: [
    ['some-plugin', {}],
    ['some-plugin', {}, 'some unique name'],
  ]

Duplicates detected are:
[
  {
    "alias": "/Users/jweber/projects/ember-api-docs/node_modules/ember-compatibility-helpers/comparision-plugin.js",
    "options": {
      "emberVersion": "3.26.1",
      "root": "/Users/jweber/projects/ember-api-docs",
      "name": "@ember/ordered-set"
    },
    "dirname": "/Users/jweber/projects/ember-api-docs",
    "ownPass": false,
    "file": {
      "request": "/Users/jweber/projects/ember-api-docs/node_modules/ember-compatibility-helpers/comparision-plugin.js",
      "resolved": "/Users/jweber/projects/ember-api-docs/node_modules/ember-compatibility-helpers/comparision-plugin.js"
    }
  },
  {
    "alias": "/Users/jweber/projects/ember-api-docs/node_modules/ember-compatibility-helpers/comparision-plugin.js",
    "options": {
      "emberVersion": "3.26.1",
      "root": "/Users/jweber/projects/ember-api-docs",
      "name": "@ember/ordered-set"
    },
    "dirname": "/Users/jweber/projects/ember-api-docs",
    "ownPass": false,
    "file": {
      "request": "/Users/jweber/projects/ember-api-docs/node_modules/ember-compatibility-helpers/comparision-plugin.js",
      "resolved": "/Users/jweber/projects/ember-api-docs/node_modules/ember-compatibility-helpers/comparision-plugin.js"
    }
  }
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Not very nice.&lt;/p&gt;

&lt;p&gt;We did &lt;code&gt;yarn why @ember/ordered-set&lt;/code&gt; to confirm that only one version of that dependency was in use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn why @ember/ordered-set

yarn why v1.22.10
[1/4] 🤔  Why do we have the module "@ember/ordered-set"...?
[2/4] 🚚  Initialising dependency graph...
[3/4] 🔍  Finding dependency...
[4/4] 🚡  Calculating file sizes...
=&amp;gt; Found "@ember/ordered-set@4.0.0"
info Reasons this module exists
   - "ember-data" depends on it
   - Hoisted from "ember-data#@ember#ordered-set"
   - Hoisted from "ember-data#@ember-data#record-data#@ember#ordered-set"
info Disk size without dependencies: "44KB"
info Disk size with unique dependencies: "1.98MB"
info Disk size with transitive dependencies: "47.57MB"
info Number of shared dependencies: 151
✨  Done in 1.83s.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Chris hypothesized that this was due to floating dependencies. Yarn and NPM let developers specify a range of acceptable dependency versions. Sometimes there are mismatches. It's often a good initial step to try deleting node modules and the lock file, as a small experiment, and then try again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; node_modules
&lt;span class="nb"&gt;rm &lt;/span&gt;yarn.lock
yarn &lt;span class="nb"&gt;install
&lt;/span&gt;npx ember s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That resolved the error about duplicate plugins!&lt;/p&gt;

&lt;h2&gt;
  
  
  On to the next error - dependencies of dependencies
&lt;/h2&gt;

&lt;p&gt;Next, we saw some errors about &lt;code&gt;ember-popper&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We looked to see what was using &lt;code&gt;ember-popper&lt;/code&gt; using &lt;code&gt;yarn why&lt;/code&gt;. One of our dependencies, &lt;code&gt;ember-styleguide&lt;/code&gt; used it. We looked at a more recent version of &lt;code&gt;ember-styleguide&lt;/code&gt;, in the &lt;code&gt;package.json&lt;/code&gt;. The latest ember-styleguide didn't even use popper, so upgrading ember-styleguide got us over this hurdle.&lt;/p&gt;

&lt;p&gt;We also saw an error about &lt;code&gt;ember-basic-dropdown&lt;/code&gt;. &lt;code&gt;yarn why&lt;/code&gt; told us it was used by &lt;code&gt;ember-power-select&lt;/code&gt;. Upgrading &lt;code&gt;ember-power-select&lt;/code&gt; and following instructions in the CHANGELOG fixed that issue.&lt;/p&gt;

&lt;p&gt;Now, when we did &lt;code&gt;yarn install&lt;/code&gt; and &lt;code&gt;npx ember s&lt;/code&gt;, the app built successfully.&lt;/p&gt;

&lt;h2&gt;
  
  
  Debugging runtime errors
&lt;/h2&gt;

&lt;p&gt;Now when we visted &lt;code&gt;localhost:4200&lt;/code&gt;, we saw something strange. The app would render for a moment (thanks to Fastboot), but then when the app's JavaScript loaded in fully, it crashed.&lt;/p&gt;

&lt;p&gt;Apps that use Fastboot show their errors in the terminal running the server, &lt;em&gt;not&lt;/em&gt; the browser console. So, to get a closer look at what was going on, we temporarily turned off fastboot by visiting &lt;code&gt;http://localhost:4200?fastboot=false&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;There were two errors in the browser console:&lt;/p&gt;

&lt;p&gt;One:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Error occurred:

- While rendering:
  -top-level
    application
      es-header
        es-navbar
          bs-navbar
            bs-navbar/content
              bs-collapse
                bs-navbar/nav
                  search-input
                    ember-tether
                      search-input/dropdown
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Uncaught (in promise) ReferenceError: process is not defined
    &amp;lt;anonymous&amp;gt; Ember
    js vendor.js:173080
    __webpack_require__ vendor.js:172838
    &amp;lt;anonymous&amp;gt; Ember
    js vendor.js:173069
    __webpack_require__ vendor.js:172838
    &amp;lt;anonymous&amp;gt; Ember
    js vendor.js:173126
    __webpack_require__ vendor.js:172838

...and a whole lot more
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We wanted to see where the problem was coming from, as step one. We commented out the &lt;code&gt;es-header&lt;/code&gt; component and saw the app render. Then we commented out pieces of the app until we got to identifying &lt;code&gt;search-input&lt;/code&gt; as the culprit.&lt;/p&gt;

&lt;p&gt;The search feature of this app comes from a third-party library. Is something in there using &lt;code&gt;process&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;I enabled "Break on exceptions" in my browser's debugging tools. This showed us that indeed, &lt;code&gt;process.env&lt;/code&gt; was being used in a third party script. But why did this work before? What else had changed?&lt;/p&gt;

&lt;h2&gt;
  
  
  Debugging webpack
&lt;/h2&gt;

&lt;p&gt;The webpack errors are a clue about what changed. When we updated a bunch of things in &lt;code&gt;package.json&lt;/code&gt; using &lt;code&gt;ember-cli-update&lt;/code&gt;, one of them was &lt;code&gt;ember-auto-import&lt;/code&gt;. This package uses webpack to bring npm dependencies into an Ember app with zero config, and we changed its versions.&lt;/p&gt;

&lt;p&gt;One thing that changed was that certain polyfills were no longer included. This was outlined &lt;a href="https://github.com/ef4/ember-auto-import#i-upgraded-my-ember-auto-import-version-and-now-things-dont-import-what-changed"&gt;in the project README&lt;/a&gt;&lt;br&gt;
along with steps to fix it.&lt;/p&gt;

&lt;p&gt;We added the following to our &lt;code&gt;ember-cli-build.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;autoImport: {
  webpack: { 
    node: { 
      process: 'mock'
    }
  }
},
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, the app rendered successfully! We removed &lt;code&gt;?fastboot=false&lt;/code&gt; from our localhost URL, and saw that it was working fine in that mode too.&lt;/p&gt;

&lt;h2&gt;
  
  
  Up next
&lt;/h2&gt;

&lt;p&gt;So, the app rendered, but the tests are failing.&lt;br&gt;
Coming soon, we'll tackle those test failures.&lt;/p&gt;

</description>
      <category>ember</category>
    </item>
    <item>
      <title>Remodeling an Ember App - Introduction</title>
      <dc:creator>Jen Weber</dc:creator>
      <pubDate>Thu, 03 Jun 2021 14:06:37 +0000</pubDate>
      <link>https://dev.to/jenweber/remodeling-an-ember-app-introduction-8p8</link>
      <guid>https://dev.to/jenweber/remodeling-an-ember-app-introduction-8p8</guid>
      <description>&lt;p&gt;In a series of blog posts, we'll go on a journey together to remodel an older Ember app, incrementally bringing it up to date with the latest and best Ember and Ember Data patterns.&lt;/p&gt;

&lt;p&gt;We will walk through updating a complex, real-world app,&lt;br&gt;
&lt;a href="https://github.com/ember-learn/ember-api-docs"&gt;ember-api-docs&lt;/a&gt;, which is the front end of &lt;a href="https://api.emberjs.com"&gt;api.emberjs.com&lt;/a&gt;. Along the way, you will learn how to approach this process for your own apps - updating dependencies, debugging build errors, migrating to Octane syntax, writing better Ember Data serializers &amp;amp; adapters... there's a lot to do!&lt;/p&gt;

&lt;p&gt;For this series, I'm pair programming with Chris Thoburn, aka &lt;a href="https://github.com/runspired"&gt;@runspired&lt;/a&gt;, who is known for his work on Ember Data. He has over 500 commits and some great debugging skills that you and I can learn from.&lt;/p&gt;

&lt;h2&gt;
  
  
  Preparation
&lt;/h2&gt;

&lt;p&gt;The focus of this first article will be about deciding where to begin, what kind of mindset to have, and an overview of the debugging tools in our toolbox. There are a lot of things we &lt;em&gt;could&lt;/em&gt; work on improving in this app, and there are multiple paths we could take that lead to success.&lt;/p&gt;

&lt;h3&gt;
  
  
  Areas of focus
&lt;/h3&gt;

&lt;p&gt;Making a list of them and prioritizing is very important step for any app refactor or upgrade. Some broad tasks to consider include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Updating to the latest package versions&lt;/li&gt;
&lt;li&gt;Resolving deprecations&lt;/li&gt;
&lt;li&gt;Running codemods&lt;/li&gt;
&lt;li&gt;Refactoring confusing stuff&lt;/li&gt;
&lt;li&gt;Documentation&lt;/li&gt;
&lt;li&gt;Testing and QA&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Making a detailed list
&lt;/h3&gt;

&lt;p&gt;Thinkig about these areas of focus helps me get started with making a detailed list.&lt;/p&gt;

&lt;p&gt;Chris Thoburn and I did a brainstorm about &lt;code&gt;ember-api-docs&lt;/code&gt; and came up with the following list:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Upgrade Ember and Ember data versions&lt;/li&gt;
&lt;li&gt;Run some codemods for Octane&lt;/li&gt;
&lt;li&gt;rewrite computed properties to cached getters, simplifying where possible (reduce intermediary computed properties)&lt;/li&gt;
&lt;li&gt;Figure out how to use less of Ember Data&lt;/li&gt;
&lt;li&gt;Figure out what needs to be in API response meta&lt;/li&gt;
&lt;li&gt;audit models and remove async relationships that didn't need to be async and ensure that inverses were properly wired&lt;/li&gt;
&lt;li&gt;make sure the API returned the format the store expects, and remove the serializer entirely&lt;/li&gt;
&lt;li&gt;Remove the adapter and replace it with one that just does a simple fetch request&lt;/li&gt;
&lt;li&gt;drop both the adapter and the serializer package and the ember-data package, instead installing store and model and record-data directly&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Prioritizing
&lt;/h3&gt;

&lt;p&gt;Next up is prioritizing. This can be hard to do when you don't know an app well, and that's ok. This list's ordering should shift over time as you learn new things! But you do need to decide what to try first.&lt;/p&gt;

&lt;p&gt;For this app, the clear first step is to upgrade the Ember and Ember Data versions.&lt;/p&gt;

&lt;p&gt;We start here so that we have all the latest and greatest features. This can also be a challenging step because shifting dependency versions sometimes reveal bugs, but finding them later in the middle of a refactor is no fun.&lt;/p&gt;

&lt;h3&gt;
  
  
  Getting in the right mindset
&lt;/h3&gt;

&lt;p&gt;Overhauling an app (or even a complex component) takes a different mindset than I use in my usual daily coding. Most days, I have expectations about how the code works, because I wrote it or studied a section of it closely. But in an overhaul, big upgrade, or refactor, there are a lot of unknowns! If I intentionally adopt a different mindset at the beginning of a big uprade, I'm a happier developer. What's that mindset look like?&lt;/p&gt;

&lt;p&gt;When I make a change that does not fix a problem, I try to be curious about why.&lt;/p&gt;

&lt;p&gt;When I see a different error, I treat it as a step forward.&lt;/p&gt;

&lt;p&gt;I keep a list of my successes as I go, including learning new things or getting one step deeper into the process.&lt;/p&gt;

&lt;p&gt;When I get stuck, I conduct small experiments, and record the results.&lt;/p&gt;

&lt;p&gt;I accept and expect that some of my experiments will be dead ends.&lt;/p&gt;

&lt;p&gt;When I don't know where an error is coming from, I focus on trying to find the source before trying to fix the error.&lt;/p&gt;

&lt;p&gt;I am skeptical of the things I changed, by default. This especially includes what's in the node_modules folder and shifting dependency versions.&lt;/p&gt;

&lt;h3&gt;
  
  
  General debugging strategies
&lt;/h3&gt;

&lt;p&gt;Over the course of this series, we will use lots of different debugging techniques. You will see examples of all of these over the coming weeks. However, it's useful to look at them as a group, and think of this as tools in your toolbox.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Selectively commenting things out from your app to hone in on where a problem is coming from. Chris calls this "bisecting," and I call it "Cat in the Hat" debugging. Identifying the areas that are &lt;em&gt;not&lt;/em&gt; a problem is progress!&lt;/li&gt;
&lt;li&gt;Cleaning out &lt;code&gt;node_modules&lt;/code&gt; - deleting the app's &lt;code&gt;node_modules&lt;/code&gt; folder and the lock file, either &lt;code&gt;package-lock.json&lt;/code&gt; or &lt;code&gt;yarn.lock&lt;/code&gt;, and reistalling dependencies&lt;/li&gt;
&lt;li&gt;Restarting the local server - important to do if you change dependency versions or build configuration&lt;/li&gt;
&lt;li&gt;Logging template values to the console. In your &lt;code&gt;.hbs&lt;/code&gt; files, you can add &lt;code&gt;{{log this.myVariable}}&lt;/code&gt; and see the output in the console&lt;/li&gt;
&lt;li&gt;If your app is using it, turning &lt;code&gt;fastboot&lt;/code&gt; off while you debug. Add &lt;code&gt;?fastboot=false&lt;/code&gt; to the end of your locally served URL, i.e. &lt;code&gt;http://localhost:4200/?fastboot=false&lt;/code&gt;. &lt;/li&gt;
&lt;li&gt;Using "Break on exceptions" or "Break on uncaught exceptions" in your browser's debugging tools, to help with finding out where errors are coming from, with some more informative context&lt;/li&gt;
&lt;li&gt;Using &lt;code&gt;debugger&lt;/code&gt; in your &lt;code&gt;js&lt;/code&gt; files to set breakpoints that you can see in your browser's debugging tools&lt;/li&gt;
&lt;li&gt;Using &lt;code&gt;yarn why package-name&lt;/code&gt; or &lt;code&gt;npm ls package-name&lt;/code&gt; to confirm which versions of dependencies are actually in use, and which other dependencies use them.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Up next
&lt;/h2&gt;

&lt;p&gt;Next, in Part 2, we will start doing the app version upgrade!&lt;/p&gt;

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