<?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: orelzion</title>
    <description>The latest articles on DEV Community by orelzion (@orelzion).</description>
    <link>https://dev.to/orelzion</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%2F89973%2Fdc5b4f39-c9b5-4d04-9838-65e619c9d33d.png</url>
      <title>DEV Community: orelzion</title>
      <link>https://dev.to/orelzion</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/orelzion"/>
    <language>en</language>
    <item>
      <title>I tried vibe coding, and survived to tell (well kinda) - Part 1</title>
      <dc:creator>orelzion</dc:creator>
      <pubDate>Sun, 10 Aug 2025 09:38:26 +0000</pubDate>
      <link>https://dev.to/orelzion/i-tried-vibe-coding-and-survived-to-tell-well-kinda-5815</link>
      <guid>https://dev.to/orelzion/i-tried-vibe-coding-and-survived-to-tell-well-kinda-5815</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt; I'm still in the early stages of the project; vibe coding is fine and all — until you need to do something that's slightly customized. Then, a developer's eye is needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  📖 The Why
&lt;/h2&gt;

&lt;p&gt;Ok, ok, let me start the story like it should—from the beginning.&lt;/p&gt;

&lt;p&gt;So, I'm writing a book (it's about being moral, but you never asked, so I won't tell), and when I was searching for ways to properly edit and design it, I came across several options but didn't like any of them.&lt;/p&gt;

&lt;p&gt;They were either too complicated or cost more than I wished to afford.&lt;br&gt;&lt;br&gt;
I spent hours researching and asking ChatGPT for brilliant ways to overcome this, but to no avail.&lt;/p&gt;

&lt;p&gt;But then myself told me: "Orel! You're a programmer, right?"&lt;br&gt;&lt;br&gt;
"Well, yes," I replied, as I am quite polite.&lt;br&gt;&lt;br&gt;
"Then why," myself continued, "don't you develop an app tailored to your needs by yourself?!"&lt;/p&gt;

&lt;p&gt;I must admit that myself posed a good question, but I didn't want to admit it — so I came up with an even better idea:&lt;br&gt;&lt;br&gt;
"You know what?" I told myself, "why write an app when you clearly don't know enough JS, when you can vibe code it?"&lt;/p&gt;

&lt;p&gt;Oh, did I not mention? I'm a mobile developer; I barely know the basics of web development. So I went to ask the smartest person I know.&lt;/p&gt;

&lt;p&gt;No, not me, I'm not that pretentious.&lt;br&gt;&lt;br&gt;
I meant ChatGPT.&lt;/p&gt;

&lt;p&gt;So I asked him, and he agreed with myself. Now they were two against one, so I had to do the democratic thing and agree.&lt;/p&gt;

&lt;p&gt;And thus began the crazy journey of a mobile developer vibe coding his first desktop app. Stay tuned—there will be bears 🐻.&lt;/p&gt;
&lt;h2&gt;
  
  
  🛠️ The Plan
&lt;/h2&gt;

&lt;p&gt;I started by asking ChatGPT to come up with a plan. We discussed my needs, technologies, and features until I thought it was enough.&lt;/p&gt;

&lt;p&gt;Then, I asked it to craft a PRD and created a new directory on my computer.&lt;/p&gt;

&lt;p&gt;I ran &lt;a href="https://www.anthropic.com/claude-code" rel="noopener noreferrer"&gt;Claude Code&lt;/a&gt; from the VSCode terminal and asked it to read the PRD first and explain what its plan was to develop it.&lt;/p&gt;

&lt;p&gt;Claude Code is my favorite AI code assistant. I like that it's a CLI tool and that it seems to really understand the requirements of the project.&lt;/p&gt;

&lt;p&gt;It gave me a comprehensive plan, broken down into steps and divided into MVP and future implementation milestones. After some back and forth with it, I agreed to the plan.&lt;/p&gt;

&lt;p&gt;Then I asked it to write that plan down into a &lt;code&gt;development_plan.md&lt;/code&gt; file so we would have a reference.&lt;/p&gt;

&lt;p&gt;We decided to use &lt;code&gt;react&lt;/code&gt; for the frontend, built on top of &lt;a href="https://v2.tauri.app/" rel="noopener noreferrer"&gt;Tauri&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I saved my project and was ready to start coding—or, actually, vibe coding.&lt;/p&gt;
&lt;h2&gt;
  
  
  🚩 The Struggle
&lt;/h2&gt;

&lt;p&gt;The first struggle came when I asked Claude to start with installation. To its credit, it did try — but it kept failing. Eventually, I told it to just give me instructions and I'd handle the heavy lifting myself.&lt;/p&gt;

&lt;p&gt;I reverted all generated code and went through the installation process on my own: the Tauri CLI, the NPM packages, everything I needed. At last, everything was ready, and I did my first commit.&lt;/p&gt;

&lt;p&gt;Then I asked it to save our progress to a &lt;code&gt;development_log.md&lt;/code&gt; file so we could track progress. I ran &lt;code&gt;/clear&lt;/code&gt; to reset the context and &lt;a href="https://youtu.be/EssztxE9P28?si=Yb-hvsKA5hkS9koC" rel="noopener noreferrer"&gt;save money&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Next, I asked what our next step was, and it went ahead and started developing. I approved everything without reading the code. I mean, I could’ve, but this is vibe coding we’re doing—and like I said, I’m not a web developer.&lt;/p&gt;

&lt;p&gt;Anyway, it tried to run the app but had a hard time doing it from the CLI. So I told it I'd run it from the terminal myself. A good choice, and you’ll see why later.&lt;/p&gt;

&lt;p&gt;The first iteration was great: the editor was usable, I could write text, emphasize it, and do text-editor-y stuff. Excited, I asked it to add a chapters menu—and it did!&lt;/p&gt;

&lt;p&gt;I asked for more steps, but then my session was stopped. You see, my Claude subscription is the $20/month one, and I have a limit on tokens. So after a while, I got blocked. Kindly, it showed me when I could return to vibe — so I waited.&lt;/p&gt;
&lt;h2&gt;
  
  
  😍 The Honeymoon
&lt;/h2&gt;

&lt;p&gt;Waiting can teach you patience. And patience is everything, or something — I don’t know, I’m not great at Buddhism. Anyway, after my detention time ended, I returned to programming.&lt;/p&gt;

&lt;p&gt;We reviewed the structure of the saved files and agreed on how to store the markdown content. But something kept breaking. No matter how hard Claude tried to get the saving feature working, it wouldn’t cooperate.&lt;/p&gt;

&lt;p&gt;Then I realized a permission was probably missing. I mentioned this, and we searched together. Turns out, it did request the permission—but the Tauri package was missing, so I installed it manually. Once I did that, saving worked smoothly.&lt;/p&gt;

&lt;p&gt;We went back and forth on other features and made great progress. We implemented themes, I18N, tons of text features, chapters, and subchapters — I really felt like I didn’t need to do anything. An entire app was being built by a computer. Amazing.&lt;/p&gt;

&lt;p&gt;I got so excited I told anyone reckless enough to ask how it was going.&lt;/p&gt;

&lt;p&gt;And then I read the code...&lt;/p&gt;

&lt;p&gt;I discovered it didn’t always implement I18N and had hardcoded strings scattered throughout. It also didn’t consistently follow the theme approach and used inline styling in random places.&lt;/p&gt;

&lt;p&gt;So I read more about it and realized I needed to add a &lt;code&gt;CLAUDE.md&lt;/code&gt; file with proper instructions. I used Claude’s code to generate it, naturally.&lt;/p&gt;

&lt;p&gt;In this file, I stated some rules, like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;## Important Rules
- **NEVER run the Tauri app** – always tell the user what to test and let them test manually
- **ALWAYS use i18n text** – never hard code strings, use translation keys from i18n config
- **Structure components in folders** – organize components into logical folder structures
- **No automatic tests** – we don’t run automated tests, manual testing only
- **ONLY use react-icons** – never use SVGs, always use icons from react-icons/fa6 package
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It also explained the project purpose, the technologies, and basically everything Claude needed to know. Now it mostly complies with my preferences — and if not, I just mention it broke the rules, and it apologizes and fixes things immediately.&lt;/p&gt;

&lt;p&gt;I mean, I’d prefer it didn’t break the rules in the first place, but you know what they say: “You can’t have it all.”&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyca0gzh314zvjh34mvq9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyca0gzh314zvjh34mvq9.png" alt="Claude Code interface" width="800" height="369"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  💻 The Debug
&lt;/h2&gt;

&lt;p&gt;Debugging with Claude is surprisingly pleasant. No, I really mean it.&lt;/p&gt;

&lt;p&gt;After some trial and error, I discovered the best way to actually fix problems: tell it to add logs.&lt;/p&gt;

&lt;p&gt;Yes, plain old logs.&lt;/p&gt;

&lt;p&gt;I just review the logs, paste them into Claude, and suddenly it understands exactly where the problem stems from.&lt;/p&gt;

&lt;p&gt;This feels a lot like pair programming to me.&lt;/p&gt;

&lt;p&gt;Of course, sometimes — or should I say too many times — Claude claims it figured out the problem and fixed it, only for you to test the app and discover it's gotten worse.&lt;/p&gt;

&lt;p&gt;But let's be honest: how many times has that happened to you? Don’t answer me.&lt;/p&gt;

&lt;p&gt;Still, this isn't quite the same. Like I said, I’m not a web developer, so I can't really verify that Claude isn't writing complete nonsense. But sometimes you just sense something's off.&lt;/p&gt;

&lt;p&gt;You know what I mean? Like you can't read TypeScript code, but you recognize a code smell when you see one.&lt;/p&gt;

&lt;p&gt;You notice how it sprinkles &lt;code&gt;setTimeout&lt;/code&gt; calls throughout the code and you're not sure why, but you're pretty sure that's not how things should work.&lt;/p&gt;

&lt;p&gt;So you ask why, and Claude responds with something like "You're right, let's completely change that." Then it rewrites everything and the app stops working entirely.&lt;/p&gt;

&lt;p&gt;Moments like this lead to great frustration. Honestly, there were times when I thought this whole thing was a big mistake, and I just couldn't fight with it anymore.&lt;/p&gt;

&lt;p&gt;Over time, I learned how to question it properly.&lt;/p&gt;

&lt;p&gt;If it tries to fix some problem in a way that looks odd to you, just stop and ask why — like why did it choose this particular solution?&lt;/p&gt;

&lt;p&gt;Sometimes you need to tell it to go look up the problem on the internet. Hell, sometimes I did it myself, came up with a solution, told Claude about it, and it implemented it perfectly.&lt;/p&gt;

&lt;p&gt;So yes, don’t automatically accept every one of its fixes. Question it.&lt;/p&gt;

&lt;p&gt;For example, if there's an error with a library it's using, Claude might just completely change it and use another library. You need to stop it from doing so and tell it to show pros and cons of that library — or to search for the issue online first. Just so you know, Claude can search the internet—it just won’t do it unless you specifically ask for it.&lt;/p&gt;

&lt;h2&gt;
  
  
  🐻 The Bears
&lt;/h2&gt;

&lt;p&gt;Ok, ok, so there were no bears, I’m sorry for that. But we did reach the end of this post, and that's something, isn't it?&lt;/p&gt;

&lt;p&gt;If you followed along, you saw that I have my moments with Claude's code. Sometimes I'm like “God, this is genius - I love you!” and other times I'm like “How can you be so stupid?”&lt;/p&gt;

&lt;p&gt;But this isn't really the end. I'm only at the beginning of the project, so other posts will surely follow.&lt;/p&gt;

&lt;p&gt;Maybe there weren’t any bears — yet. But give it time. Claude might generate one.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>claudecode</category>
      <category>programming</category>
    </item>
    <item>
      <title>First impressions on Maestro - The simplest mobile testing framework</title>
      <dc:creator>orelzion</dc:creator>
      <pubDate>Sat, 17 Sep 2022 19:13:51 +0000</pubDate>
      <link>https://dev.to/orelzion/first-impressions-on-maestro-the-simplest-mobile-testing-framework-2neg</link>
      <guid>https://dev.to/orelzion/first-impressions-on-maestro-the-simplest-mobile-testing-framework-2neg</guid>
      <description>&lt;p&gt;&lt;small&gt;Photo by &lt;a href="https://unsplash.com/@markwilliamspics?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Mark Williams&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/conductor?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;Last week I participated in &lt;a href="https://twitter.com/droidconNYC" rel="noopener noreferrer"&gt;Droidcon NYC&lt;/a&gt; and outside the main conference room was a stand of &lt;a href="https://www.mobile.dev/" rel="noopener noreferrer"&gt;mobile.dev&lt;/a&gt;. I usually don't stop at stands (unless I see some great t-shirts or socks 😄) but something caught my eyes.&lt;/p&gt;

&lt;p&gt;It was this demo&lt;br&gt;
&lt;iframe class="tweet-embed" id="tweet-1565004345355079680-189" src="https://platform.twitter.com/embed/Tweet.html?id=1565004345355079680"&gt;
&lt;/iframe&gt;

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



&lt;/p&gt;

&lt;p&gt;What caught my eye was the simplicity of this framework. I have some experience with &lt;a href="https://developer.android.com/training/testing/espresso" rel="noopener noreferrer"&gt;Espresso&lt;/a&gt; and I know how hard it is to write the same test in it.&lt;/p&gt;

&lt;p&gt;So I promised myself to go and check it out when I return, and so I did.&lt;/p&gt;

&lt;p&gt;In this post I'll share my first impressions and maybe this article will actually become a series 😄&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;Installation was actually a breeze, I head over to the &lt;a href="https://maestro.mobile.dev/getting-started/installing-maestro" rel="noopener noreferrer"&gt;guide&lt;/a&gt; and everything is explained there.&lt;/p&gt;

&lt;p&gt;I decided to first install it locally, and since I want to test both Android and iOS I didn't install it into &lt;code&gt;gradle&lt;/code&gt; but via &lt;code&gt;homebrew&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Android
&lt;/h3&gt;

&lt;p&gt;Running my first test on Android was easy.&lt;/p&gt;

&lt;p&gt;I created a new file &lt;code&gt;simple_login_test.yml&lt;/code&gt; that looks like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;appId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ai.viz.notifier"&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;launchApp&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;clearState&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, I headed over to Android Studio to open an emulator.&lt;/p&gt;

&lt;p&gt;And then I run this line from my terminal&lt;br&gt;
&lt;code&gt;maestro test simple_login_flow.yml&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And that was it! &lt;br&gt;
The app has launched!&lt;/p&gt;
&lt;h3&gt;
  
  
  iOS
&lt;/h3&gt;

&lt;p&gt;For iOS though things have been a little bit harder.&lt;/p&gt;

&lt;p&gt;I first needed to add another installation from &lt;code&gt;homebrew&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;brew tap facebook/fb
brew install idb-companion
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a library from Facebook that will allow us to connect to an iOS simulator.&lt;/p&gt;

&lt;p&gt;After installing run this command in your terminal&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;idb_companion --list 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;it will list all of the available simluators, find one that you like (for me it was iPhone 13 mini) and copy its &lt;code&gt;udid&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Then you will launch it with this command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;idb_companion --boot 85921D77-E655-4FA4-B202-D705E66E0D8A
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After it's launch you'll need to connect to it with this command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;idb_companion --udid 85921D77-E655-4FA4-B202-D705E66E0D8A
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you should be able to start your test.&lt;/p&gt;

&lt;p&gt;So I created another file &lt;code&gt;simple_login_flow-ios.yml&lt;/code&gt; with the same code just replacing the android's appId with a iOS' bundle id.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;appId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;viz.ai.VizAINotifier"&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;launchApp&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;clearState&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But it didn't launch 😥&lt;/p&gt;

&lt;p&gt;Apparently I had to shut down the Android emulator first, and only then it launched.&lt;/p&gt;

&lt;p&gt;I guess they first try to find if there's an Android emulator and if there is they will try to launch on it. Then, it didn't find any app with that appId, so it just quite the test.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running a simple flow
&lt;/h2&gt;

&lt;p&gt;So the first flow we're going to run is a simple login flow. I want to launch the app, enter wrong credentials, see an error, fix the credentials and login successfully.&lt;/p&gt;

&lt;p&gt;Simple, right?&lt;/p&gt;

&lt;p&gt;Well, with other frameworks (Espresso ☕️ I'm looking at you 👀), this would take one class to set all the views to their IDs, another to launch the app and dozen functions or so to interact and assert it.&lt;/p&gt;

&lt;p&gt;If you have to wait between actions, you'd have to also implement a timer to keep checking if your view is already displayed.&lt;/p&gt;

&lt;p&gt;Not with maestro!&lt;/p&gt;

&lt;p&gt;In here, to start the app all I need is this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;appId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ai.viz.notifier"&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;launchApp&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;clearState&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To tap a button to continue to the login screen, all I need is&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Welcome screen (yes, this is a comment)&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;tapOn&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;GET STARTED&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To do some assertions on views, to check that the views that suppose to be there are actually there, I needed&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;assertVisible&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Email"&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;assertNotVisible&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Password"&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;assertNotVisible&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Reset&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Password"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The way that this works is that instead of looking for a view id, it looks for the text, the same way as your QA engineer will do it.&lt;/p&gt;

&lt;p&gt;But what if you &lt;strong&gt;don't have a text&lt;/strong&gt;? I wanted to assert if some icon was showing.&lt;/p&gt;

&lt;p&gt;Fortunately, you &lt;strong&gt;can use&lt;/strong&gt; IDs as well.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;assertVisible&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ai.viz.notifier:id/fingerPrintButton"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Maestro hierarchy
&lt;/h3&gt;

&lt;p&gt;How did I get this id? Do I need yo open Android Studio and try to find it there? Hell no!&lt;/p&gt;

&lt;p&gt;We want simplicity and simplicity will shall get 😄&lt;/p&gt;

&lt;p&gt;To get all the views from a current screen, just run &lt;code&gt;maestro hierarchy&lt;/code&gt; in your command line. The output will be all your view tree, with texts and IDs.&lt;/p&gt;

&lt;p&gt;This is how I knew what ID to use here.&lt;/p&gt;

&lt;h3&gt;
  
  
  Other assertions
&lt;/h3&gt;

&lt;p&gt;I did have one more thing I wanted to test.&lt;/p&gt;

&lt;p&gt;In our app we disable the next button if you don't have text, this is part of the QA process and I wanted Maestro to do the same, but I didn't find any option to assert whether or not a view is clickable. &lt;/p&gt;

&lt;p&gt;So I asked in their &lt;a href="https://join.slack.com/t/mobile-dev-inc/shared_invite/zt-1f0nl7zsx-DndKtQmR0YvK9QdvSAgpwA" rel="noopener noreferrer"&gt;Slack channel&lt;/a&gt; whether they plan on having more assertions types.&lt;/p&gt;

&lt;p&gt;And this is how they answered&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvmflahci4xmpfsa4szz8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvmflahci4xmpfsa4szz8.png" alt="maestro philosophy" width="409" height="744"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Make sense!&lt;/p&gt;

&lt;p&gt;So what I did was to tap on the button and check that the screen hasn't changed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;assertVisible&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Email"&lt;/span&gt;
&lt;span class="c1"&gt;# Test next button is disable when no text entered&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;tapOn&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Next"&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;assertVisible&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Email"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  iOS
&lt;/h2&gt;

&lt;p&gt;I have other assertions in my file but I won't bore you with details 😄.&lt;/p&gt;

&lt;p&gt;I now wanted to have the same test with iOS.&lt;/p&gt;

&lt;p&gt;I started with the same test&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;appId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;viz.ai.VizAINotifier"&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;launchApp&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;clearState&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;assertVisible&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Enter&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;your&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;email"&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;assertNotVisible&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Password"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But my first assertion failed. Although the text was there as a hint in the edit text, Maestro didn't find it.&lt;/p&gt;

&lt;p&gt;So I posted another question in the slack channel.&lt;/p&gt;

&lt;p&gt;Just 3 days after reporting, the issue got fixed!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmrm86gso9ynqjlw5ihgw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmrm86gso9ynqjlw5ihgw.png" alt="fixing maestro" width="568" height="563"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is an amazing pace for a library, and I think that this shows how hard they work to improve it and this is indeed a good sign.&lt;/p&gt;

&lt;p&gt;But to test the icon that was there, I didn't test by its ID, in iOS it actually use the image id as the text, so I was able to test it like this,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;assertVisible&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sfIcon60"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Problems?
&lt;/h3&gt;

&lt;p&gt;But then I got stuck, after the initial login flow, we have a view pager for a walkthrough. But no matter what I tried I wasn't able to test it.&lt;/p&gt;

&lt;p&gt;Running &lt;code&gt;maestro hierarchy&lt;/code&gt; on this screen gave me absolutely nothing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;orelzion@N&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="err"&gt;QFJYD&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="err"&gt;GW&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;maestro&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;maestro&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;hierarchy&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"attributes"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"children"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"attributes"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"VizDebug"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"bounds"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"[0,0][375,812]"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"children"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"clickable"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"attributes"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"resource-id"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"screen.onboarding.container"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"bounds"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"[0,0][375,812]"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"children"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"clickable"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"clickable"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I was also trying to ask in the Slack channel, but this time, although they did try to help me, it just didn't work.&lt;/p&gt;

&lt;p&gt;I'm guessing I'm gonna need to investigate that some more to understand what is so special about this screen 😄.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrap up
&lt;/h2&gt;

&lt;p&gt;This post will probably have a follow up, the maestro framework is great! Super simple and intuitive, and I liked the philosophy of it.&lt;/p&gt;

&lt;p&gt;This is defiantly a library that I will continue to investigate, and I look forward to integrate that into our projects.&lt;/p&gt;

&lt;p&gt;Stay tuned! &lt;/p&gt;

</description>
      <category>mobile</category>
      <category>testing</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Optimising markers performance on Google Maps using RxJava</title>
      <dc:creator>orelzion</dc:creator>
      <pubDate>Sun, 14 Oct 2018 17:22:30 +0000</pubDate>
      <link>https://dev.to/orelzion/optimising-markers-perofrmence-on-google-maps-using-rxjava-5622</link>
      <guid>https://dev.to/orelzion/optimising-markers-perofrmence-on-google-maps-using-rxjava-5622</guid>
      <description>&lt;p&gt;So today I ran into an interesting problem. I needed to display a large amount of markers on Google Map, and we decided that too many markers will just not look good, and so we are eliminating markers that intersect by over 70 percent, and display just one of them instead.&lt;/p&gt;

&lt;p&gt;And so I wrote this little function that takes two Rect objects to see if they intersect.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fuf9pmnczuwh6pamgjwop.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fuf9pmnczuwh6pamgjwop.png" width="800" height="847"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But how do you get a rect object if all you have is a Lat/Lng of where you want to position your marker?&lt;br&gt;
Well, luckily for us Google Maps already has a utility function, that converts a lat/lng on map into a Point object. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;mGoogleMap.getProjection().toScreenLocation(latLng)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And so, I was able to create a Rect object based on that point plus the icon width and height.&lt;/p&gt;

&lt;p&gt;Now we need to iterate over all lat/lngs and check which of them are intersecting.&lt;/p&gt;

&lt;p&gt;Since this can be heavy (iterating over each object and check it against all other object in the list), I decided to run it inside an RxJava observable. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fz6w3izorywxbdzppcq0d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fz6w3izorywxbdzppcq0d.png" width="800" height="294"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Seems legit, right?&lt;/p&gt;

&lt;p&gt;Well, I thought, let's give it a run. Oh boy, that sucked terribly. I ran the app on a Google Pixel 2 device, and whenever I moved the screen and the markers needed redrawing, the app just stuck for a second.&lt;/p&gt;

&lt;p&gt;So I looked at my code again, and although the method 'getPoiForVisibleRegion' is running in the background, the map operation that comes next is not! This is so because I only added the subscribeOn and observeOn methods inside 'getPoiForVisibleRegion' so the map operation that was called later was not included.&lt;/p&gt;

&lt;p&gt;Ok, so I just need to include the subscribe method after the map declaration, right?&lt;/p&gt;

&lt;p&gt;Not so fast, my friend.&lt;br&gt;
Here's the catch. Google Maps can't get you the screen point while in background, so that means that I was able to run every other parts of my algorithm in RxJava but the intersection filter. &lt;/p&gt;

&lt;p&gt;Back to the drawing table then.&lt;/p&gt;

&lt;p&gt;Now I thought, what if I could get all the points for the currently visible markers before the filter, and make the actual filter run in background when it already has all the points?&lt;/p&gt;

&lt;p&gt;And so I did just that. I created a HashMap that updates every time the map bounds changes (so that means zoom level has changed, or the map moves). I get the currently visible region of the map while still on the UI thread&lt;/p&gt;

&lt;p&gt;&lt;code&gt;mGoogleMap.getProjection().getVisibleRegion().latLngBounds;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Then I go and filter out only the markers that I should draw now. And I save a mapping between those locations to their point on screen&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fktflh1zb3nsl26qo3kjf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fktflh1zb3nsl26qo3kjf.png" width="800" height="309"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Viola! &lt;/p&gt;

&lt;p&gt;The result was very satisfying! The map moves smoothly and the markers are getting removed or appeared on screen with a nice animation (not described in this post), without the user has to wait more than a fraction of a second, and more importantly without the screen ever gets stuck&lt;/p&gt;

</description>
      <category>android</category>
      <category>googlemaps</category>
      <category>rxjava</category>
    </item>
  </channel>
</rss>
