<?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/"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
>
	<channel>
		<title> - Mozilla</title>
		<description>Posts categorized as 'mozilla'</description>
		<sy:updatePeriod>daily</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>
		<link>https://brizental.github.io</link>
		<atom:link href="https://brizental.github.io/feed.mozilla.xml" rel="self" type="application/rss+xml" />
		<lastBuildDate>Wed, 07 Apr 2021 17:00:00 +0000</lastBuildDate>
		
		
			<item>
				<title>This Week in Glean: Publishing Glean.js or How I configured an npm package that has multiple entry points</title>
				<description>&lt;p&gt;&lt;em&gt;(“This Week in Glean” is a series of blog posts that the Glean Team at Mozilla is using to try to
communicate better about our work. They could be release notes, documentation, hopes, dreams, or
whatever: so long as it is inspired by Glean. You can find
&lt;a href=&quot;https://mozilla.github.io/glean/book/appendix/twig.htm&quot;&gt;an index of all TWiG posts online&lt;/a&gt;).&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;All “This Week in Glean” blog posts are listed in the &lt;a href=&quot;https://mozilla.github.io/glean/book/appendix/twig.html&quot;&gt;TWiG index&lt;/a&gt;
(and on the &lt;a href=&quot;https://blog.mozilla.org/data/category/glean/&quot;&gt;Mozilla Data blog&lt;/a&gt;).
This article is &lt;a href=&quot;https://blog.mozilla.org/data/2021/04/07/this-week-in-glean-publishing-glean-js/&quot;&gt;cross-posted on the Mozilla Data blog&lt;/a&gt;.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;A few weeks ago, it came the time for us to publish the first version of Glean.js in npm. (Yes,
it has been published. Go &lt;a href=&quot;https://www.npmjs.com/package/@mozilla/glean&quot;&gt;take a look&lt;/a&gt;). In order
to publish a package on npm, it is important to define the package entry points in the project’s
&lt;a href=&quot;https://nodejs.org/api/packages.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;package.json&lt;/code&gt;&lt;/a&gt; file. The entry point is the path to the file
that should be loaded when users import a package through &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;import Package from &quot;package-name&quot;&lt;/code&gt; or
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;const Package = require(&quot;package-name&quot;)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;My knowledge in this area went as far as “Hm, I think that &lt;a href=&quot;https://docs.npmjs.com/cli/v7/configuring-npm/package-json#main&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;main&lt;/code&gt;&lt;/a&gt;
field in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;package.json&lt;/code&gt; is where we define the entry point, right?”. Yes, I was right about that,
but it turns out that was not enough for Glean.js.&lt;/p&gt;

&lt;h2 id=&quot;the-case-of-gleanjs&quot;&gt;The case of Glean.js&lt;/h2&gt;

&lt;p&gt;Glean.js is an implementation of Glean for Javascript environments. “Javascript environments” can
mean multiple things: Node.js servers, Electron apps, websites, webextensions… The list goes on.
To complicate things, Glean.js needs to access a bunch of platform specific APIs such as client
side storage. We designed Glean.js in such a way that platform specific code is abstracted away under
the &lt;a href=&quot;https://github.com/mozilla/glean.js/tree/main/glean/src/platform&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Platform&lt;/code&gt;&lt;/a&gt; module, but when
users import Glean.js all of this should be opaque.&lt;/p&gt;

&lt;p&gt;So, we decided to provide a different package entry point per environment. This way, users can import
the correct Glean for their environments and not care about internal architecture details e.g.
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;import Glean from &quot;glean/webext&quot;&lt;/code&gt; imports the version of Glean that uses the web extensions
implementaion of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Platform&lt;/code&gt; module.&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;main&lt;/code&gt; field I mentioned above works when the package has one single entry point. What do you
do when the package has multiple entry points?&lt;/p&gt;

&lt;h2 id=&quot;the-exports-field&quot;&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;exports&lt;/code&gt; field&lt;/h2&gt;

&lt;p&gt;Lucky for us, starting from Node v12.7.0, Node recognizes the
&lt;a href=&quot;https://nodejs.org/api/packages.html#packages_exports&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;exports&lt;/code&gt;&lt;/a&gt; field in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;package.json&lt;/code&gt;.
This field accepts objects, so you can define mappings for all your package entry points.&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;glean&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;exports&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;./webext&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;path/to/entry/point/webext.js&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;./node&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;path/to/entry/point/node.js&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;Another nice thing about the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;exports&lt;/code&gt; field, is that it denies access to any other entry point
that is not defined in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;exports&lt;/code&gt; map. Users can’t just import any file in your package anymore.
Neat.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We must also define entry points for the type declarations of our package. Type declarations are
necessary for users attempting to import the package in Typescript code. Glean.js is in Typescript,
so it is easy enough for us to &lt;em&gt;generate&lt;/em&gt; the type definitions, but we hit a wall when want to expose
the generated definitions. From the &lt;a href=&quot;https://www.typescriptlang.org/docs/handbook/declaration-files/publishing.html#including-declarations-in-your-npm-package&quot;&gt;“Publishing”&lt;/a&gt;
page on Typecript’s documentation, this is the example provided:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;awesome&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;author&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Vandelay Industries&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;version&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;1.0.0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;main&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;./lib/main.js&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;types&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;./lib/main.d.ts&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Notice the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;types&lt;/code&gt; property. It works just like the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;main&lt;/code&gt; property. It does not accept an object,
only a single entry point. And here we go again, what do you do when the package has multiple
entry points?&lt;/p&gt;

&lt;h2 id=&quot;the-typesversions-workaround&quot;&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;typesVersions&lt;/code&gt; workaround&lt;/h2&gt;

&lt;p&gt;This time I won’t say “Lucky for us Typescript has this other property starting from version…”.
Turns out Typescript, as I am writing this blog post, doesn’t yet provide a way for packages to define
multiple entry points for their types declarations.&lt;/p&gt;

&lt;p&gt;Typescript lets packages define different types declarations per Typescript version,
through the &lt;a href=&quot;https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-1.html#version-selection-with-typesversions&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;typesVersions&lt;/code&gt;&lt;/a&gt;
property. This property does accept mappings of entry points to files. Smart people on the internet
figured out, that we can use this property to define different types declarations for each of our
package entry points. For more discussion on the topic, follow issue &lt;a href=&quot;https://github.com/microsoft/TypeScript/issues/33079&quot;&gt;#33079&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Back to our previous example, type definitions mappings would look like this in our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;package.json&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;glean&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;exports&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;./webext&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;path/to/entry/point/webext.js&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;./node&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;path/to/entry/point/node.js&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;typesVersions&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;*&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;./webext&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;path/to/types/definitions/webext.d.ts&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;./node&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;path/to/types/definitions/node.d.ts&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Alright, this is great. So we are done, right? Not yet.&lt;/p&gt;

&lt;h2 id=&quot;conditional-exports&quot;&gt;Conditional exports&lt;/h2&gt;

&lt;p&gt;Our users can finally import our package in Javascript and Typescript and they have well
defined entry points to choose from depending on the platform they are building for.&lt;/p&gt;

&lt;p&gt;If they are building for Node.js though, they still might encounter issues. The default module system
used by Node.js is &lt;a href=&quot;https://nodejs.org/docs/latest/api/modules.html#modules_modules_commonjs_modules&quot;&gt;commonjs&lt;/a&gt;.
This is the one where we import packages by using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;const Package = require(&quot;package&quot;)&lt;/code&gt; syntax
and export modules by using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;module.exports = Package&lt;/code&gt; syntax.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://nodejs.org/api/esm.html&quot;&gt;Newer versions of Node&lt;/a&gt;, also support the &lt;a href=&quot;https://tc39.es/ecma262/#sec-modules&quot;&gt;ECMAScript module system&lt;/a&gt;
, also known as ESM. This is the offical Javascript module system and is the one where we import
packages by using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;import Package from &quot;package&quot;&lt;/code&gt; syntax and export modules by using the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;export default Package&lt;/code&gt; syntax.&lt;/p&gt;

&lt;p&gt;Packages can provide different builds using each module system. In the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;exports&lt;/code&gt; field, Node.js
allows packages to define different export paths to be imported depending on the module system
a user is relying on. This feature is called &lt;a href=&quot;https://nodejs.org/api/packages.html#packages_conditional_exports&quot;&gt;“conditional exports”&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Assuming you have gone through all the setup involved in building a hybrid NPM module for both
ESM and CommonJS (to learn more about how to do that, refer to &lt;a href=&quot;https://www.sensedeep.com/blog/posts/2021/how-to-create-single-source-npm-module.html&quot;&gt;this great blog post&lt;/a&gt;),
this is how our example can be changed to use conditional exports:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;glean&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;exports&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;./webext&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;path/to/entry/point/webext.js&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;./node&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;import&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;path/to/entry/point/node.js&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;require&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;path/to/entry/point/node.cjs&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;typesVersions&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;*&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;./webext&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;path/to/types/definitions/webext.d.ts&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;./node&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;path/to/types/definitions/node.d.ts&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The same change is not necessary for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;./webext&lt;/code&gt; entry point, because users building for browsers
will need to use bundlers such as &lt;a href=&quot;https://webpack.js.org/&quot;&gt;Webpack&lt;/a&gt; and &lt;a href=&quot;https://rollupjs.org/guide/en/&quot;&gt;Rollup&lt;/a&gt;,
which have their own implementation of import/require statement resolutions and are able to import
both ESM and CommonJS modules either &lt;a href=&quot;https://webpack.js.org/guides/ecma-script-modules/#flagging-modules-as-esm&quot;&gt;out-of-the-box&lt;/a&gt;
or through &lt;a href=&quot;https://github.com/rollup/plugins/tree/master/packages/commonjs&quot;&gt;plugins&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Note that there is also no need to change the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;typesVersions&lt;/code&gt; value for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;./node&lt;/code&gt; after this change.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;final-considerations&quot;&gt;Final considerations&lt;/h2&gt;

&lt;p&gt;Although the steps in this post look straightforward enough, it took me quite a while to figure out
the correct way to configure the Glean.js’ entry points. I encountered many caveats along the way, such
as the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;typesVersions&lt;/code&gt; workaround I mentioned above, but also:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;In order to support ES6 modules, it is necessary to include the filename and extension in all internal
package import statements. CommonJS infers the extension and the filename when it is not provided,
but ES6 doesn’t. This get’s extra weird in Glean.js’ codebase, because Glean.js is in Typescript
and all our import statements still have the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.js&lt;/code&gt; extension. See more discussion about this on
&lt;a href=&quot;https://github.com/microsoft/TypeScript/issues/16577#issuecomment-754941937&quot;&gt;this issue&lt;/a&gt; and
&lt;a href=&quot;https://github.com/mozilla/glean.js/pull/123/commits/607c9d5285298f7afbc6187d3b2bdd7d0c1f25b3&quot;&gt;our commit with this change&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;Webpack, below version 5, does not have support for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;exports&lt;/code&gt; field and is not able to import a
package that defined entry points only using this feature. See the &lt;a href=&quot;https://webpack.js.org/blog/2020-10-10-webpack-5-release/#major-changes-new-nodejs-ecosystem-features&quot;&gt;Webpack 5 release notes&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;Other exports conditions such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;browser&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;production&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;development&lt;/code&gt; are mentioned
in the &lt;a href=&quot;https://nodejs.org/api/packages.html#packages_conditions_definitions&quot;&gt;Node.js documentation&lt;/a&gt;,
but are ultimately ignored by Node.js. They are used by bundlers such as Webpack and Rollup. The Webpack
documentation has &lt;a href=&quot;https://webpack.js.org/guides/package-exports/#conditions&quot;&gt;a comprehensive list of all the conditions&lt;/a&gt;
you can possibly include in that list, which bundler supports each, and whether Node.js supports it too.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hope this guide is helpful to other people on the internet. Bye! 👋&lt;/p&gt;
</description>
				<pubDate>Wed, 07 Apr 2021 17:00:00 +0000</pubDate>
				<link>https://brizental.github.io/2021/04/07/publishing-glean-js.html</link>
				<guid isPermaLink="true">https://brizental.github.io/2021/04/07/publishing-glean-js.html</guid>
			</item>
		
			<item>
				<title>This Week in Glean: Glossary</title>
				<description>&lt;p&gt;(“This Week in Glean” is a series of blog posts that the Glean Team at Mozilla is using to try to communicate better about our work. They could be release notes, documentation, hopes, dreams, or whatever: so long as it is inspired by Glean. You can find &lt;a href=&quot;https://mozilla.github.io/glean/book/appendix/twig.html&quot;&gt;an index of all TWiG posts online.&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;Last blog post: &lt;a href=&quot;https://brizental.github.io/2019/12/06/this-week-in-glean-migrations.html&quot;&gt;This Week in Glean: Migrations&lt;/a&gt; by me.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;I am the newest Glean team member, having joined October/2019. One of the most challenging parts of understanding our product and our code base these past months has been keeping up with terminology. Coming from a web development background, some of the terms used in Glean have slight or big differences in meaning from that context. This has been an exercise in resignifying or flat out learning new words from the English language.&lt;/p&gt;

&lt;p&gt;This blog post will be a sort of glossary with explanations and background on the terms that stood out to me.&lt;/p&gt;

&lt;h3 id=&quot;the-glossary&quot;&gt;The glossary&lt;/h3&gt;

&lt;h4 id=&quot;glean-not-glean-or-glean&quot;&gt;“Glean”, not “GLEAN” or “glean”&lt;/h4&gt;

&lt;p&gt;I think it is appropriate to start with the name of the product. Contrary to what I thought before joining the team, “Glean” is not an acronym. This may be obvious to those who already know the word, but I didn’t and the logo can be misleading since all the letters are capitalized.&lt;/p&gt;

&lt;figure class=&quot;image&quot;&gt;
  &lt;img src=&quot;https://raw.githubusercontent.com/mozilla/glean/master/docs/glean.jpeg&quot; alt=&quot;The Glean logo. To know more about it, see &amp;lt;a href='https://dianaciufo.wordpress.com/2019/10/11/glean-graphic-identity-for-mozilla-firefox/' target='_blank'&amp;gt;This Week in Glean: What is the Glean logo about?&amp;lt;/a&amp;gt;&quot; /&gt;
  &lt;figcaption&gt;The Glean logo. To know more about it, see &lt;a href=&quot;https://dianaciufo.wordpress.com/2019/10/11/glean-graphic-identity-for-mozilla-firefox/&quot; target=&quot;_blank&quot;&gt;This Week in Glean: What is the Glean logo about?&lt;/a&gt;&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;According to &lt;a href=&quot;https://www.merriam-webster.com/dictionary/glean&quot;&gt;the dictionary&lt;/a&gt; the word “glean” means:&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;to gather information or material bit by bit&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There are other meanings to it, of course. The one I quoted is the one that makes the most sense given what Glean is about.&lt;/p&gt;

&lt;p&gt;I should also note that Glean is not a synonym to The Glean SDK, which is part, but not the whole of the Glean product. For more on “what is Glean exactly”, refer to &lt;a href=&quot;https://docs.telemetry.mozilla.org/concepts/glean/glean.html&quot;&gt;the documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Finally, as suggested by the title of this section, the “official” way to write “Glean”, is by capitalizing the word. Not all caps, not non-capitalized.&lt;/p&gt;

&lt;h4 id=&quot;metric&quot;&gt;“metric”&lt;/h4&gt;

&lt;p&gt;Metrics are the individual things being measured using Glean. They are defined in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;metrics.yaml&lt;/code&gt; files. Glean itself provides some metrics out of the box and looking at its own &lt;a href=&quot;https://github.com/mozilla/glean/blob/master/glean-core/metrics.yaml&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;metrics.yaml&lt;/code&gt;&lt;/a&gt; we can see some examples of what a metric can be:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The metric &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;glean.baseline.duration&lt;/code&gt; of type &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;timespan&lt;/code&gt; holds “The duration of the last foreground session.”&lt;/li&gt;
  &lt;li&gt;The metric &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;glean.internal.metrics.os&lt;/code&gt; of type &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;string&lt;/code&gt; holds “The name of the operating system.”&lt;/li&gt;
  &lt;li&gt;The metric &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;glean.internal.metrics.first_run_date&lt;/code&gt; of type &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;datetime&lt;/code&gt; holds “The date of the first run of the application.”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In previous versions of telemetry the word “probe” was used to describe a metric. The Glean team decided not to use that word anymore because it can be misleading since its meaning is not accurate to what a metric is.&lt;/p&gt;

&lt;p&gt;For more information or questions on how to define or set metrics, refer to &lt;a href=&quot;https://mozilla.github.io/glean/book/user/adding-new-metrics.html&quot;&gt;The Glean SDK Book&lt;/a&gt;.&lt;/p&gt;

&lt;h4 id=&quot;ping&quot;&gt;“ping”&lt;/h4&gt;

&lt;p&gt;In the Glean context, a ping is an entity used to bundle related metrics. Out of the box the Glean SDK provides four default pings: the baseline ping, the metrics ping, the events ping, and the deletion-request ping. The Glean SDK also provides a way for the user to define their own custom pings.&lt;/p&gt;

&lt;p&gt;For more information on custom or default pings, refer to &lt;a href=&quot;https://mozilla.github.io/glean/book/user/pings/index.html&quot;&gt;The Glean SDK Book&lt;/a&gt;.&lt;/p&gt;

&lt;h4 id=&quot;submission&quot;&gt;“submission”&lt;/h4&gt;

&lt;p&gt;In the Glean context, “to submit” means the &lt;em&gt;to collect + to upload&lt;/em&gt; a ping.&lt;/p&gt;

&lt;p&gt;The Glean SDK stores locally all the metrics set by it or by its clients. Each ping has its own schedule to gather all its locally saved metrics and create a JSON payload with them (e.g. every time the app goes to background for the baseline ping, or everyday at 4am for the metrics ping). This is called “collection”.&lt;/p&gt;

&lt;p&gt;Upon successful collection, the payload is queued for upload, which may not happen immediately or at all (in case network connectivity is not available).&lt;/p&gt;

&lt;p&gt;Unless the user has defined their own custom pings, they don’t need to worry too much about submitting pings. All the default pings have their scheduling and submission handled by the SDK.&lt;/p&gt;

&lt;p&gt;For information on how to submit pings, refer to &lt;a href=&quot;https://mozilla.github.io/glean/book/user/pings/custom.html#submitting-a-custom-ping&quot;&gt;The Glean SDK Book&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;Naming is hard and consistency is key.&lt;/p&gt;
</description>
				<pubDate>Fri, 10 Jan 2020 12:30:00 +0000</pubDate>
				<link>https://brizental.github.io/2020/01/10/this-week-in-glean-glossary.html</link>
				<guid isPermaLink="true">https://brizental.github.io/2020/01/10/this-week-in-glean-glossary.html</guid>
			</item>
		
			<item>
				<title>This Week in Glean: Migrations</title>
				<description>&lt;p&gt;(“This Week in Glean” is a series of blog posts that the Glean Team at Mozilla is using to try to communicate better about our work. They could be release notes, documentation, hopes, dreams, or whatever: so long as it is inspired by Glean. You can find &lt;a href=&quot;https://mozilla.github.io/glean/book/appendix/twig.html&quot;&gt;an index of all TWiG posts online.&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;Last week’s blog post: &lt;a href=&quot;https://fnordig.de/2019/11/29/this-week-in-glean/&quot;&gt;This Week in Glean: Differences&lt;/a&gt; by jan-erik.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;The Glean team has spent a bunch of 2019 rewriting the Glean SDK (which was initially written in Kotlin) in Rust and by the end of October we finally released that rewrite into the world. For more on that, refer to the previous TWiG blog post by jan-erik: &lt;a href=&quot;https://fnordig.de/2019/10/24/this-week-in-glean/&quot;&gt;A Release&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Of course, as with any major rewrite, we had to put some mechanisms in place so that a client that needed to transition from a previous version did so without any major problems. For Glean, that meant data migrations. Each metric type was locally stored a bit differently in the Kotlin implementation than it is now in the Rust one, so that had to be changed. The migration code was to be run the first time the updated Glean was initialized and only once.&lt;/p&gt;

&lt;p&gt;To be sure that our users were migrating as expected, &lt;a href=&quot;https://github.com/mozilla/glean/pull/334/files&quot;&gt;telemetry was added&lt;/a&gt; to know everytime a user migrated successfully.&lt;/p&gt;

&lt;p&gt;Now that the Rust version had been released, it was time for us to check back on that and see if our users were migrating correctly. For that, I created two queries, one to verify that:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Only users who should have migrated (e.g. sent pings in previous versions), recorded successful migrations;&lt;/li&gt;
  &lt;li&gt;Users have recorded the successful migration only once;&lt;/li&gt;
  &lt;li&gt;Users have only recorded successful migrations from versions above 19 – which is the minimum version where they should.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And another one to verify that:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;For the daily clients that should have migrated, they all have done so.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The first query gave us positive results, with no or very little clients showing any of the problems we were looking for. Great!&lt;/p&gt;

&lt;p&gt;The second query, also gave positive results with ~97,5% of our daily clients having recorded succesful migrations. Unfortunately, those ~2,5% that did not record successful migrations were a concern that needed to be verified.&lt;/p&gt;

&lt;p&gt;Off I went to write yet more SQL, the question I wanted to answer this time being:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Are the daily users that have not migrated always the same ones? Or are we getting different users everyday?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Since I didn’t know how to answer exactly that with only SQL, I changed the question to:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;How many &lt;a href=&quot;https://mozilla.github.io/glean/book/user/pings/metrics.html#crossing-due-time-with-the-application-closed&quot;&gt;metrics pings&lt;/a&gt; does a user send after updating, but before recording the successful migration?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I found that for the users that &lt;strong&gt;have&lt;/strong&gt; recorded successful migrations, usually that count ranges between 0-2 pings, but for the users that &lt;strong&gt;haven’t&lt;/strong&gt; recorded the successful migration the count is between 1-73 pings.&lt;/p&gt;

&lt;p&gt;(It should be noted, that in a perfect world, all users should send 0 pings after updating, but before migration. Migration should happen immediatelly and all pings should happen after that, but that is not happening due to &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1601960&quot;&gt;another issue&lt;/a&gt;.)&lt;/p&gt;

&lt;p&gt;Back to the users that haven’t recorded a successful migration: the fact that they have recorded so many pings without recording the migration are already an indication that they have successfully migrated and for some reason haven’t added that to the ping. Because of the way the migration was implemented, if the user doesn’t successfully migrate, they will get a new client id, thus making it impossible for us to relate their pings from the new version with their pings from previous versions.&lt;/p&gt;

&lt;p&gt;And that is that! I have still to find out why some clients are not correctly recording the successful migration and if you are curious about that, check on &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1599999&quot;&gt;this bug&lt;/a&gt;. I might have found that out by the time you read this blog post.&lt;/p&gt;
</description>
				<pubDate>Fri, 06 Dec 2019 16:30:00 +0000</pubDate>
				<link>https://brizental.github.io/2019/12/06/this-week-in-glean-migrations.html</link>
				<guid isPermaLink="true">https://brizental.github.io/2019/12/06/this-week-in-glean-migrations.html</guid>
			</item>
		
			<item>
				<title>End of Outreachy</title>
				<description>&lt;p&gt;So, Outreachy is officially over and I can’t express how much I loved it. Mike was the greatest mentor that I could ask for, super patient and helpful, but at the same let me do what I really wanted to. I will continue working with the Webcompat team, because I really liked the problems and also because there is still a lot of stuff to do regarding functional and unit tests.&lt;/p&gt;

&lt;p&gt;I was lucky enough to get an internship that will start on the day after Outreachy ends, so I won’t be unemployed for any time at all.&lt;/p&gt;

&lt;p&gt;The end of Outreachy also doesn’t mean the end of this blog. I really enjoyed sharing my experiences here, it helps me think and review a lot of stuff. I’ll try and continue writing everytime that I can or when I get something really cool to share.&lt;/p&gt;

&lt;p&gt;That’s it for now. ‘Till next time.&lt;/p&gt;
</description>
				<pubDate>Sat, 16 Sep 2017 17:12:00 +0000</pubDate>
				<link>https://brizental.github.io/2017/09/16/end-of-outreachy.html</link>
				<guid isPermaLink="true">https://brizental.github.io/2017/09/16/end-of-outreachy.html</guid>
			</item>
		
			<item>
				<title>BrazilJS Conference</title>
				<description>&lt;p&gt;Outreachy gives us a grant of up top $500 for traveling, be it for a conference, a workshop, a course, anything that has something to do with the Open Source Community. My mentor, Mike Taylor, was going to come to BrazilJS and asked me if I wanted to use my travel allowance for it, I agreed and went to the conference that happened in Porto Alegre.&lt;/p&gt;

&lt;h4 id=&quot;braziljs&quot;&gt;BrazilJS&lt;/h4&gt;

&lt;p&gt;BrazilJS is self proclaimed as the “biggest Javascript conference in the universe” and roughly 1.500 people attend it every year in Brazil. My mentor, Mike Taylor, lived in Brazil for sometime in his life and knows how to speak Portuguese really well. He has been attending the conference for the past years and this year was no exception. Since I live in Sao Paulo, Outreachy gives a travel allowance, and in my work I use a lot of Javascript, it made a lot of sense for me to go with, and I did.&lt;/p&gt;

&lt;p&gt;Mike was going to give a talk there about “weird APIs” and Mozilla itself was going to have a booth about WebVR and A-Frame, so I went as a Mozilla employee.&lt;/p&gt;

&lt;p&gt;The conferece went on for two days and I watched a lot of great talks. The ones that I enjoyed the most were the WebVR ones “3D Experiences + The Web Platform” and “A-Frame 101”. The first one was mostly just a presentation of stuff that you can do with three.js, A-Frame and Web Assembly and the second was an introduction and showcase of A-Frame and it’s features.&lt;/p&gt;

&lt;h4 id=&quot;a-frame&quot;&gt;A-Frame&lt;/h4&gt;

&lt;p&gt;I have to make a section only for A-Frame in this blog post, because it is too awesome.&lt;/p&gt;

&lt;p&gt;As I understand it, A-Frame is a wrapper around the three.js framework and makes it super really easy to build virtual reality experiences with just HTML and JavaScript. The feature that left me awed was the inspector one. Basically, when you have an A-Frame scene in a webpage, you can add the inspector feature to it just my injecting some JavaScript to the page. When you open it, you can press &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Alt+Shift+i&lt;/code&gt; and instead of the browser inspector opening up, the A-Frame inspector will.&lt;/p&gt;

&lt;p&gt;The A-Frame inspector is a simple yet powerful 3D modeling tool for the browser. You can add, move, change, update, animate and do a lot of cool stuff to 3D models and scenes directly from the browser.&lt;/p&gt;

&lt;p&gt;I will add links to all this in the related links section for this post.&lt;/p&gt;

&lt;h4 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h4&gt;

&lt;p&gt;BrazilJS was my first ever conference. If I’m being really honest, I have a really hard time just staying put and watching talks, but I really don’t think that a conference is all about that. Of course the talks are really important, but what I brought home with me that I treasure more than the talks that I watched were the people that I met, the stories that I listened to, the experiences that I shared with everyone that I met there and of course the t-shirts that I got.&lt;/p&gt;

&lt;h4 id=&quot;related-links&quot;&gt;Related Links&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://braziljs.org/conf/&quot;&gt;BrazilJS Website&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://aframe.io/&quot;&gt;A-Frame Website&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/aframevr/aframe-inspector&quot;&gt;A-Frame Inspector Repository&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
				<pubDate>Fri, 01 Sep 2017 17:12:00 +0000</pubDate>
				<link>https://brizental.github.io/2017/09/01/braziljs-conference.html</link>
				<guid isPermaLink="true">https://brizental.github.io/2017/09/01/braziljs-conference.html</guid>
			</item>
		
			<item>
				<title>Promises and async / await with Intern.js</title>
				<description>&lt;p&gt;As I mentioned in my previous blog post about Browserstack, I got a lot of errors when I tried to run our Intern.js functional tests in browsers other than Chrome and Firefox. I left this issue aside at the time, because it was too saturated in my mind, but I decided to give it another go these past two weeks.&lt;/p&gt;

&lt;h4 id=&quot;understanding-how-internjs-works&quot;&gt;Understanding how Intern.js works&lt;/h4&gt;

&lt;p&gt;The framework that we use for Javascript functional testing is Intern.js. Intern.js has a tool called Leadfoot, that puts a layer of abstraction over the Selenium WebDriver API and makes it cross browser compatible.&lt;/p&gt;

&lt;p&gt;Here is an example of a simple Intern.js test that we have in the Webcompat tests:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&quot;Comments form visible when logged in&quot;: function() {
    return (
      FunctionalHelpers.openPage(this, url(&quot;/issues/100&quot;), &quot;.js-Issue&quot;)
        // Comment form visible for logged in users.
        .findDisplayedByCssSelector(&quot;.js-Comment-form&quot;)
        .end()
    );
  },
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Each one of the functions that is called inside of the tests return a promise.&lt;/p&gt;

&lt;h4 id=&quot;debugging-safari-tests&quot;&gt;Debugging Safari tests&lt;/h4&gt;

&lt;p&gt;The first thing I did to start debugging the Safari tests was modify the Intern.js config file to have the tests run on Safari. After I ran them a bunch of times, I realized that most of the errors I was getting were actually intermittent (they happened randomly). I fixed a lot of other intermittent errors in the tests before, and all of them where latency problems. Some function would return after or before expected.&lt;/p&gt;

&lt;p&gt;Since all of the Intern.js/Leadfoot functions return Promises, I thought that maybe it was a problem of a function that resolved after expected and broke the code. So, I took one single test that failed in Safari continuously and decided to use it as a proof of concept.&lt;/p&gt;

&lt;p&gt;The test before I changed anything looked like this:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&quot;Add a screenshot to a comment&quot;: function() {
    return FunctionalHelpers.openPage(
      this,
      url(&quot;/issues/100&quot;),
      &quot;.wc-Comment-body&quot;
    )
      .findById(&quot;image&quot;)
      .type(&quot;tests/fixtures/green_square.png&quot;)
      .end()
      .sleep(2000)
      .findByCssSelector(&quot;.js-Comment-text&quot;)
      .getProperty(&quot;value&quot;)
      .then(function(val) {
        assert.include(
          val,
          &quot;[![Screenshot Description](http://localhost:5000/uploads/&quot;,
          &quot;The image was correctly uploaded and its URL was copied to the comment text.&quot;
        );
      })
      .end();
  },
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I tried to modify it to call the Promises in a synchronous manner, which means, only call the next function once the previous one has resolved. The code looked horrible, but it worked, the test started passing. Here is what it looked like:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&quot;Add a screenshot to a comment&quot;: function() {
	var remote = FunctionalHelpers.openPage(
	  this,
	  url(&quot;/issues/100&quot;),
	  &quot;.wc-Comment-body&quot;,
	    true
	  );
	  return (
	    remote
	      // Find image upload input.
	      .findById(&quot;image&quot;)
	      .then(function(el) {
	        el
	          // Type fixture image path into it.
	          .type(require.toUrl(&quot;../fixtures/green_square.png&quot;))
	          .then(function() {
	            remote
	              .end()
	              // Find the comment textarea.
	              .findByCssSelector(&quot;.js-Comment-text&quot;)
	              .then(function(el) {
	                el
	                  // Get it's value.
	                  .getProperty(&quot;value&quot;)
	                  .then(function(val) {
	                    // Check that the value is what expected.
	                    assert.include(
	                      val,
	                      &quot;[![Screenshot Description](http://localhost:5000/uploads/&quot;,
	                      &quot;The image was correctly uploaded and its URL was copied to the comment text.&quot;
	                    );
	                  });
	              });
	          });
	      })
	      .end()
	  );
},
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;At the moment we have a total of 76 functional tests in 17 different files. It would be very difficult to maintain code like this. It’s too extensive and difficult to read. So I started researching some other way to write it and make it look good and be easy to maintain, that’s when I stumbled upon &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async / await&lt;/code&gt;.&lt;/p&gt;

&lt;h4 id=&quot;understanding-async--await&quot;&gt;Understanding async / await&lt;/h4&gt;

&lt;p&gt;When you have code that is heavy with Promises, async / await is a great tool to help you organize and synchronize your code. I think the best way to understand it is with a simple example:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;function simplePromise() {
    return new Promise(function(resolve) {
        setTimeout(resolve, 10000);
    });
}

async function exampleAsync() {
	await simplePromise();
	console.log('Promise is done!');
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If you run this example in your console, you will see that ‘Promise is done!’ will only be printed after the time interval. That is what async / await does. It holds of code execution until a promise is returned. The usage is pretty simple. It’s important to note that for you to be able to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;await&lt;/code&gt; you have to be inside of an asynchronous function and for a function to asynchronous you need to add the keyword &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt; before declaring it.&lt;/p&gt;

&lt;h4 id=&quot;using-async--await-in-our-tests&quot;&gt;Using async / await in our tests&lt;/h4&gt;

&lt;p&gt;I used the same test and applied the async / await idea to it. It looked like this:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&quot;Add a screenshot to a comment&quot;: async function() {
    await FunctionalHelpers.openPage(
      this,
      url(&quot;/issues/100&quot;),
      &quot;.wc-Comment-body&quot;
    );

    let input = await this.remote.findById(&quot;image&quot;);
    await input.type(require.toUrl(&quot;../fixtures/green_square.png&quot;));

    let textarea = await this.remote.findByCssSelector(&quot;.js-Comment-text&quot;);
    let text = await textarea.getProperty(&quot;value&quot;);

    assert.include(
      text,
      &quot;[![Screenshot Description](http://localhost:5000/uploads/&quot;,
      &quot;The image was correctly uploaded and its URL was copied to the comment text.&quot;
    );
},
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This looks much better than the first time I tried the idea. Interestingly enough, it didn’t work.&lt;/p&gt;

&lt;p&gt;Unfortunately, this blog post will end in a sad note as I didn’t find out the solution for this and Safari tests are still on hold. We had some other more necessary features to add to the tests and my internship is almost over, so we left it aside, once again.&lt;/p&gt;

&lt;p&gt;If anyone knows the solution for this, please write me or open an issue in the repository for this blog.&lt;/p&gt;

&lt;h4 id=&quot;related-links&quot;&gt;Related Links&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/theintern/intern-tutorial&quot;&gt;Intern.js Tutorial with async / await examples&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://theintern.io/&quot;&gt;Intern.js Website&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function&quot;&gt;async / await Definition on MDN&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
				<pubDate>Sun, 20 Aug 2017 17:12:00 +0000</pubDate>
				<link>https://brizental.github.io/2017/08/20/promises-and-async-await.html</link>
				<guid isPermaLink="true">https://brizental.github.io/2017/08/20/promises-and-async-await.html</guid>
			</item>
		
			<item>
				<title>Travis CI and the Submission of PR's</title>
				<description>&lt;p&gt;One of the goals for my internship was to get the tests of pull requests submitted from forks to work, because they were not working and the reason was unknown. Here I will explain how I did it and how simple it was.&lt;/p&gt;

&lt;h4 id=&quot;what-is-travisci&quot;&gt;What is TravisCI&lt;/h4&gt;

&lt;p&gt;TravisCI is a continuous integration tool for GitHub test driven development. How it works is really simple, it provides us access to a remote virtual machine that we can control with a GUI and with a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.travis.yml&lt;/code&gt; file. We use this machine to run a series of commands in the branch that is being sent by the a newly submitted pull request or commit.&lt;/p&gt;

&lt;p&gt;To make things clearer, I’ll just explain how we use it in Webcompat.&lt;/p&gt;

&lt;p&gt;Everytime that a user sends in a commit or a pull request, we have a setup Travis configuration file that downloads the new code, builds the webcompat environment for development and runs the unit and functional tests to check that everything is alright. If all tests are passing, the pull request will have a small green tick after it’s title, if it doesnt’t the pull request will have a small red ‘x’ after it’s title. We can also manually re-run all tests in a pull request as many times as we want.&lt;/p&gt;

&lt;h4 id=&quot;what-was-the-problem-with-our-failing-builds&quot;&gt;What was the problem with our failing builds&lt;/h4&gt;

&lt;p&gt;In the Webcompat repository, we had a really annoying problem that was, even if all tests were passing in a pull request, if it came from a fork they would fail. That was even more annoying given that even some of our core contributors use forks instead of just using the webcompat repository.&lt;/p&gt;

&lt;p&gt;Luckly the problem was really simple.&lt;/p&gt;

&lt;p&gt;Travis has some “secure variables” that are only available to the owners of the main repository being tested. Our tests were relying in some of these secure variables, because we had to add GitHub token and secret in order to access the GitHub API for running tests. Now, the only thing I had to do was remove all these secure variables, because, as I explained in my previous blog posts, one of the things that I did to the Webcompat unit and functional tests, was mock all GitHub API calls. Everything worked.&lt;/p&gt;

&lt;h4 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h4&gt;

&lt;p&gt;Sometimes the solution for a coding problem can be super simple. When I first started to tackle this problem I was trying all this crazy workarounds and I actually didn’t even need them.&lt;/p&gt;

&lt;h4 id=&quot;related-links&quot;&gt;Related links&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.travis-ci.com/user/environment-variables/&quot;&gt;TravisCI Secure Variables Documentation&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/webcompat/webcompat.com/pull/1710&quot;&gt;The PR Where I Fixed the Secure Variables Problem&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
				<pubDate>Sat, 05 Aug 2017 17:12:00 +0000</pubDate>
				<link>https://brizental.github.io/2017/08/05/travis-ci-and-the-submission-of-prs.html</link>
				<guid isPermaLink="true">https://brizental.github.io/2017/08/05/travis-ci-and-the-submission-of-prs.html</guid>
			</item>
		
			<item>
				<title>Mocking GET requests with Python unittest.Mock</title>
				<description>&lt;p&gt;At the Mozilla All Hands, I finished getting all functional tests to work offline. Which means that I got everything to return fixture data and none of our API calls to ever go to an external website. But while in the All Hands I also realized that some tests from our Python unit tests were network dependant and needed to be mocked.&lt;/p&gt;

&lt;h4 id=&quot;unittestmock&quot;&gt;unittest.Mock&lt;/h4&gt;

&lt;p&gt;Our unit tests are written in Python, because our application is in Flask. So, to make them network independent I had to mock everything out in Python. That’s when I realized it was time to study and understand the Python unittest.Mock class. Because it provides us with a series of helper classes and methods to mock any function or object that you may need in a Python test.&lt;/p&gt;

&lt;p&gt;In my case, I only needed to mock GET requests to the GitHub API. I had to patch the API call and return the expected data. In order to do that, understanding only one concept was key for me to know what I had to do: I only needed to patch the API call to GitHub, all the logic in the Webcompat application had to stay intact, or else I would be left with testing blind spots.&lt;/p&gt;

&lt;p&gt;First I familiarized myself with the exact architecture of the webcompat application, to know which function I had to patch in order to only mock what was necessary. After doing that, it was very stright forward: patch the function and return the expected data from it.&lt;/p&gt;

&lt;p&gt;Here is an example of one of the functions that I patched. Mind you, the function that made the API call is the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;webcompat.helpers.proxy_request&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;def test_api_issues_out_of_range(self):
    '''API issue for a non existent number returns JSON 404.'''
    with patch('webcompat.helpers.proxy_request') as github_data:
        github_data.return_value = mock_api_response({
            'status_code': 404,
            'content': '[{&quot;message&quot;:&quot;Not Found&quot;,&quot;documentation_url&quot;:&quot;https://developer.github.com/v3&quot;}]'  # nopep8
        })
        rv = self.app.get('/api/issues/1', environ_base=headers)
        json_body = json.loads(rv.data)
        self.assertEqual(rv.status_code, 404)
        self.assertEqual(rv.content_type, 'application/json')
        self.assertEqual(json_body['status'], 404)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You can see that I don’t even need to return all the response that the GitHub API would, only the parts that I would need for everything to work right.&lt;/p&gt;

&lt;h4 id=&quot;related-links&quot;&gt;Related Links&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/webcompat/webcompat.com/pull/1697/files&quot;&gt;The PR with the mocking of the requests&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.python.org/3/library/unittest.mock.html&quot;&gt;unittest.Mock Documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
				<pubDate>Thu, 20 Jul 2017 17:12:00 +0000</pubDate>
				<link>https://brizental.github.io/2017/07/20/mocking-and-python-unittests.html</link>
				<guid isPermaLink="true">https://brizental.github.io/2017/07/20/mocking-and-python-unittests.html</guid>
			</item>
		
			<item>
				<title>All Hands 2017 San Francisco</title>
				<description>&lt;p&gt;Mozilla has a biannual gathering for all employees and some volunteers, it’s called the Mozilla All Hands and it always happens in a different city around the world. This year, the Summer All Hands happened in San Francsico, CA, USA and as an intern I had the priviledge to go and experience the event.&lt;/p&gt;

&lt;h4 id=&quot;about-the-all-hands-and-san-francisco&quot;&gt;About the All Hands and San Francisco&lt;/h4&gt;

&lt;p&gt;I had never gone to something like this, I had never gone to a programming conference, I hadn’t even ever gone to the United States. Needles to say, I was super excited.&lt;/p&gt;

&lt;p&gt;They let me know about the conference about a month before, for me to have time to get the plane tickets get a hotel room and prepare psychologically for the trip. Mozilla would pay for everything, so it was not much of a thinker, of course I accepted the invitation and went.&lt;/p&gt;

&lt;p&gt;The All Hands is a work week. Since many Mozilla employees work remotely or even the ones that work in offices usually have a team that is scattered aroud the globe, it’s important to have this sort of event where everybody gets together, meets, works and has fun.&lt;/p&gt;

&lt;p&gt;I arrived there around 1PM a day before the first day of the meeting. I was super excited to have a free day to walk around and get to see a little bit of San Francisco before getting to work. I was really surprised as to how the United States reminded me of Brazil. Having just come back from a three month internship in Germany, where there is a reallly big difference from Sao Paulo, I was surprised that San Francisco was not much a break from Brazil. Of course, the city is much smaller and there is the different language, but other than that, the vibe doesn’t change much.&lt;/p&gt;

&lt;p&gt;Even though it was so much like Brazil, the city was new to me so I wanted to walk around. I saw the cable car, saw the bay, went into some stores and just tried to experience as much as I could just by walking around the hotel. Luckly the hotel was in a really central area so I could see a lot. At the end of the day I was really tired, but satisfied and so I went to the welcome cocktail to the All Hands.&lt;/p&gt;

&lt;p&gt;At the cocktail I got to finally meet Mike in person and some other Mozilla employees. I didn’t stay much, because the tiredness from the almost 15 hour trip and the jetlag was starting to get to me. I decided to go to sleep so as to fully enjoy the next day.&lt;/p&gt;

&lt;h4 id=&quot;the-actual-work-week&quot;&gt;The actual work week&lt;/h4&gt;

&lt;p&gt;The first day started out with a really brief talk to get things going and explain how the week would go about. We were told that the week would not be about going to meetings and going to talks, it would be about sitting down and coding a lot with your colleagues. And that’s what we did. For the next five days I would get up in the morning, have breakfast go to the office that was setup for us and work a lot.&lt;/p&gt;

&lt;p&gt;Even though I coded so much, I don’t think that that was the best part of the week, by far. It was really great for me to get to know all the other guys from the Webcompat team and the other girls that were also Outreachy interns.&lt;/p&gt;

&lt;p&gt;It was great to hear the stories of all my other team colleagues and learn with them. I also really enjoyed getting to know what they did for the project. Some of the guys worked triaging and finding the solution for the compatibility bugs that are filed on webcompat.com, others worked improving the design of the website, others the functionality and so on, some guys were even working on browser tools to help debug the compatibilioty bugs that we get. Awesome.&lt;/p&gt;

&lt;h4 id=&quot;imposter-syndrome-workshop&quot;&gt;Imposter syndrome workshop&lt;/h4&gt;

&lt;p&gt;Aside from the coding, Mozilla provided a workshop only for the Outreachy interns about Imposter Syndrome and how to try and overcome it.&lt;/p&gt;

&lt;p&gt;Imposter Syndrome is a really common evil and specially present among girls that work in tech. Basically, it’s the feeling that you are not good enough, but so intense that it becomes almost pathological. It was great to hear the complaints, fears and ways to improve that the other girls shared during the workshop. Each one had a different story and by hearing and identifying myself with them I felt much better about me and my work. It made me feel part of something and not so alone in my struggles and fears.&lt;/p&gt;

&lt;h4 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h4&gt;

&lt;p&gt;I thought the All Hands was a key event for me to feel as if I was a part of the Mozilla team. Even though I saw the avatars and usernames of all my colleagues online, there is nothing better than meeting everyone in person. One big thing that changed for me is my online presence with the team. Now that I know everybody in person I get much less shy about talking in IRC and GitHub and in video confereces with the group.&lt;/p&gt;

&lt;p&gt;It was also great to get the time to have fun with them, not only work. I got to go to a record store with Mike (I’m a vynil collector as is he), got to eat some burritos with the rest of the team and also go to a fancy restaurant and we even did some sightseeing. All in all it was a great week.&lt;/p&gt;

&lt;h4 id=&quot;related-links&quot;&gt;Related Links&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.flickr.com/groups/sfallhands2017/&quot;&gt;Flickr Group with a lot of pictures from the meeting&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
				<pubDate>Wed, 05 Jul 2017 23:56:00 +0000</pubDate>
				<link>https://brizental.github.io/2017/07/05/san-francisco-all-hands.html</link>
				<guid isPermaLink="true">https://brizental.github.io/2017/07/05/san-francisco-all-hands.html</guid>
			</item>
		
			<item>
				<title>Cross Browser Testing with Browserstack</title>
				<description>&lt;p&gt;This will be another Outreachy diary.&lt;/p&gt;

&lt;p&gt;One of my goals for the internship was to user Browserstack for cross browser testing. That is important, because right now we are only testing in Firefox, but our users can come from any browser, so we should test with as many as possible.&lt;/p&gt;

&lt;h4 id=&quot;trying-browserstack-out&quot;&gt;Trying Browserstack out&lt;/h4&gt;

&lt;p&gt;Browserstack a “free for open source projects” tool, that let’s you use and run automated tests in remote machines with different operating systems, different browsers and even on mobile devices. Our functional tests are written using Intern.js, an awesome functional testing tool written in JavaScript, that uses Selenium to automate tests in any browser. Other than that, Intern.js has Browserstack Tunnel built in, so that the integration is painless.&lt;/p&gt;

&lt;p&gt;Even though Browserstack is a great tool, I ran into quite a lot of problems while trying to do cross browser testing with it. I’m going to list them all here.&lt;/p&gt;

&lt;h4 id=&quot;uploading-local-files&quot;&gt;Uploading local files&lt;/h4&gt;

&lt;p&gt;One of the functionalitites that we check in our Intern.js tests is file uploading. The problem that I ran into was that, even though the tests were running in the Browserstack remote machine, the path for the test file that we wanted to upload was referencing my local machine and that returned a “File not found” error.&lt;/p&gt;

&lt;p&gt;I looked for quite a while into that, but nothing seemed to work. It was a really weird error, because when I looked into Leadfoot’s documentation it explained that when you tried to upload a file through a file input the driver would seamlesly upload the file to the remote server before uploading it through the input.&lt;/p&gt;

&lt;p&gt;Anyways, I was completely lost on this issue, so I asked a question in Stack Overflow (my first question there ever) and a guy really helped me out. The only thing I needed to do was add this to the Intern.js configuration object:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;capabilities: {
    fixSessionCapabilities: true,
    remoteFiles: true,
    .
    .
    #.
  },

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;latency&quot;&gt;Latency&lt;/h3&gt;

&lt;p&gt;Now that I got the uploading out of the way, I could just start testing in different browsers. That was when I ran into another issue. It’s great to test everything in remote machines, but it has a real set back: it is really slow. Because of the latency, many tests would time out or not run at all. For that I found no solution.&lt;/p&gt;

&lt;h3 id=&quot;inconsistencies-across-browsers&quot;&gt;Inconsi#stencies across browsers&lt;/h3&gt;

&lt;p&gt;Since we only tested with Firefox, we didn’t have a real idea of how the tests would go about in diferent browsers. For starters, I tried testing with Chrome and that went well. The results were not so different from Firefox, one minor change to the tests code and everything passed.&lt;/p&gt;

&lt;p&gt;Now it was time to try out Edge. When I started the internship, Mozilla sent me a MacBook Pro, so I didn’t even have Edge to test with locally, anyways. The results were sad. Many of the tests didn’t pass, the error messages were not really clear and I couldn’t even test locally to have a better and faster development experience. I explained the issue to Mike and after checking Google Analytics and realizing that less than one percent of our users came from Edge (really should have looked at that first thing right, you live and learn) we decided to leave it aside and go back to it when we have time or if ever it becomes really important.&lt;/p&gt;

&lt;p&gt;Finally it was time to test with Safari. Those were the most depressing results of all. The majority of tests would fail in Safari remote and locally, nothing made much sense and hope was crushed. Safari is the third most used browser among our users, but still it’s not even 5% of our user base, so we decided to also leave it aside.&lt;/p&gt;

&lt;p&gt;One import observation about this section is that even though tests were not passing, it didn’t mean that the stuff being tested was not working. I tried testing manually and proved that. The problem was with Selenium or Leadfoot, so it was not crucial that we fixed it rig#ht away.&lt;/p&gt;

&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;Phew.&lt;/p&gt;

&lt;p&gt;After all this, I think I don’t even have to say that I was frustrated with Browserstack. And then I got to thinking: Do we really need to use it?&lt;/p&gt;

&lt;p&gt;I added Chrome testing to our TravisCI Pull Request automated testing code and I found out that I could use OS X in Travis as well, so that I could test Safari with it too. And that was my answer: I didn’t really need to use it.&lt;/p&gt;

&lt;p&gt;I presented to Mike my findings and he agreed that it was not necessary and we closed all issues about it.&lt;/p&gt;

&lt;p&gt;I think Browserstack is a really good tool if your application has users coming from all sorts of places from mobile devices to diferent operating systems and different browsers, but it turns out that is not the case for Webcompat. Our users come from Desktop devices almost exclusively using Firefox or Chrome and Browserstack was overkill and an unnecessary burden.&lt;/p&gt;

&lt;p&gt;Now what is left to be done is see what is going on with Safari and get all tests running with it so that we can also test there, but I think I should leave this issue aside for now since it’s too saturated in my mind at the mo#ment.&lt;/p&gt;

&lt;h3 id=&quot;related-links&quot;&gt;Related Links&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.browserstack.com/#&quot;&gt;Browserstack Website&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://theintern.io/leadfoot/&quot;&gt;Leadfoot Docs&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://stackoverflow.com/questions/45201328/how-can-i-test-an-input-type-file-with-browserstack&quot;&gt;My Stack Overflow Question&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
				<pubDate>Wed, 21 Jun 2017 17:12:00 +0000</pubDate>
				<link>https://brizental.github.io/2017/06/21/browsertack-and-cross-browser-testing.html</link>
				<guid isPermaLink="true">https://brizental.github.io/2017/06/21/browsertack-and-cross-browser-testing.html</guid>
			</item>
		
	</channel>
</rss>
