<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Guo-Guang</title>
    <description>The latest articles on Forem by Guo-Guang (@taitung).</description>
    <link>https://forem.com/taitung</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%2F70205%2Fed470fc4-c018-4656-807e-5cea53a33338.jpg</url>
      <title>Forem: Guo-Guang</title>
      <link>https://forem.com/taitung</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/taitung"/>
    <language>en</language>
    <item>
      <title>is LDAP still relevant in terms of being a security source provider?</title>
      <dc:creator>Guo-Guang</dc:creator>
      <pubDate>Tue, 05 Jun 2018 08:27:33 +0000</pubDate>
      <link>https://forem.com/taitung/is-ldap-still-relevant-in-terms-of-a-security-source-provider-34p2</link>
      <guid>https://forem.com/taitung/is-ldap-still-relevant-in-terms-of-a-security-source-provider-34p2</guid>
      <description>&lt;p&gt;I am going to work on a new project which is related to security. Currently, I am studying where to store user credential like password and token. What we have now is to store this sensitive information in MongoDB along with a user profile. Well, I am not sure if this is a good design or not. But, I would like to make a change by separating the credential and profile data to different storage like LDAP and MySQL or even MongoDB. The main difference is to store users' credential in LDAP and store profile data in either MySQL or MongoDB. Thinking of performance and security level an LDAP can provide, do you think the LDAP is still a relevant technology in such a case? Or, how do you use LDAP?&lt;/p&gt;

</description>
      <category>discss</category>
      <category>ldap</category>
      <category>security</category>
    </item>
    <item>
      <title>Have you played the puppeteer?</title>
      <dc:creator>Guo-Guang</dc:creator>
      <pubDate>Thu, 31 May 2018 14:44:59 +0000</pubDate>
      <link>https://forem.com/taitung/have-you-played-the-puppeteer-1jhh</link>
      <guid>https://forem.com/taitung/have-you-played-the-puppeteer-1jhh</guid>
      <description>&lt;p&gt;I got a chance recently working on a UI test automation project which is on top of the Google puppeteer. It's a tool highly customizable for developers to control the behavior of Google Chromium browser. The details of puppeteer can be found &lt;a href="https://github.com/GoogleChrome/puppeteer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We have a Google Chrome web extension project and the tests before each release a series of tests will be performed by interns. We have tried to maintain 100% coverage by executing the unit tests for the project. However, the integration tests like hitting APIs and monitor how the web extension UI behaves according to web pages or websites the web extension is on is still done manually. Indeed, manual tests are still important. But, we sometimes found out that the data collected by interns through manual tests are not that accurate for any kinds of reasons. We have surveyed UI test automation solutions like Selenium with WebDrivers and others but we ended up with Google puppeteer since we only support Google chrome at this stage.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/GoogleChrome/puppeteer/blob/v1.4.0/docs/api.md"&gt;APIs&lt;/a&gt; of Google Puppeteer is pretty straightforward. Starting from creating a browser is very simple like codes below&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;puppeteer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;launch&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="nx"&gt;headless&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// if true then no UI will be shown&lt;/span&gt;
    &lt;span class="na"&gt;ignoreDefaultArgs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;ignoreHTTPSErrors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;slowMo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// delay executing each actions performed on web broswer&lt;/span&gt;
    &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// other args&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Due to the test target is the browser extension, I need to specify where the browser extension is so that the Google Chromium browser can locate the assets and then start the installation. &lt;strong&gt;extPath&lt;/strong&gt; is the absolute path to the folder holding browser extensions assets.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`--disable-extensions-except=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;extPath&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`--load-extension=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;extPath&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;puppeteer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;launch&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="nx"&gt;headless&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;ignoreDefaultArgs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;ignoreHTTPSErrors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;slowMo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The codes above will show you the Google Chromium browser with the web extension icon on the top-right corner and probably open another tab landing to the website the web extension specify in &lt;a href="https://developer.chrome.com/extensions/manifest"&gt;menifest.json&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There are few key &lt;a href="https://developer.chrome.com/extensions/getstarted"&gt;components&lt;/a&gt; composing the Google web extensions. Among which, the main UI commonly called &lt;strong&gt;popup.html&lt;/strong&gt; is one of the test targets in the project. To the best of my knowledge, there no is &lt;a href="https://developer.chrome.com/extensions/api_index"&gt;API&lt;/a&gt; currently able to trigger the click event of the extension icon or button sitting on top-right corner to show the main UI which is the popup.html. However, there is a way around the issue, which is directly visiting the popup.html page. Therefore, you need to create a &lt;a href="https://github.com/GoogleChrome/puppeteer/blob/v1.4.0/docs/api.md"&gt;Page&lt;/a&gt; and specify the URL you want to visit. In codes below, there is a variable called extId. If you don't have this id you probably cannot load the popup.html.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;newPage&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// create a new tab&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;chromeExtPath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`chrome-extension://&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;extId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/popup.html`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// where to find extId?&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;goto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chromeExtPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;waitUntil&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;domcontentloaded&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bringToFront&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bringToFront&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;reload&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the normal installation, you should find out the web extensions IDs at this directory &lt;strong&gt;~/Library/Application Support/Google/Chrome/Default/Extensions&lt;/strong&gt; if you're on the Macbook. However, you won't find any IDs in this directory related to the &lt;a href="https://developer.chrome.com/extensions/hosting"&gt;unpacked&lt;/a&gt; extensions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;➜  &lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt; ~/Library/Application&lt;span class="se"&gt;\ &lt;/span&gt;Support/Google/Chrome/Default/Extensions
total 0
drwx------@ 3 guoguang  staff  96 May 21 10:33 bmnlcjabgnpnenekpadlanbbkooimhnj
drwx------@ 3 guoguang  staff  96 May 31 12:57 chhjbpecpncaggjpdakmflnfcopglcmi
drwx------@ 3 guoguang  staff  96 May 26 13:37 djjjmdgomejlopjnccoejdhgjmiappap
drwx------@ 3 guoguang  staff  96 May 30 13:59 jifpbeccnghkjeaalbbjmodiffmgedin
drwx------@ 3 guoguang  staff  96 May 31 12:55 kbfnbcaeplbcioakkpcpgfkobkghlhen
drwx------@ 3 guoguang  staff  96 May 18 14:01 niloccemoadcdkdjlinkgdfekeahmflj
drwx------@ 3 guoguang  staff  96 May 16 10:31 nmmhkkegccagdldgiimedpiccmgmieda
drwx------@ 3 guoguang  staff  96 May 16 10:31 pkedcjkdefgpdelpbcmbmeomcjbeemfm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are two methods address the missing extension id. First, &lt;a href="https://developer.chrome.com/extensions/getstarted"&gt;load the unpacked extension&lt;/a&gt; in Google Chrome browser and also turn on Developer mode to show extension ids. However, this must go through the manual process, which is a bit problematic if you want to have a fully automated testing process. The second way is to generate the extension &lt;a href="https://developer.chrome.com/apps/manifest/key"&gt;key&lt;/a&gt; and id on the fly. Following this &lt;a href="https://stackoverflow.com/questions/37317779/making-a-unique-extension-id-and-key-for-chrome-extension?rq=1"&gt;thread&lt;/a&gt; on StackOverflow about how to create the key and id I have a shell script generating key and id as follows. You probably need to enlarge the key size to 4096 while creating the pem.key so as to make the web extension id and key works out for the extensions. Btw, the Google Chromium version I am using is 68.0.3419.0 Developer Build 64-bit.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  &lt;span class="c"&gt;# genereate the web extension key.&lt;/span&gt;
  &lt;span class="nv"&gt;ret&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;openssl rsa &lt;span class="nt"&gt;-in&lt;/span&gt; ./extensions/key.pem &lt;span class="nt"&gt;-pubout&lt;/span&gt; &lt;span class="nt"&gt;-outform&lt;/span&gt; DER | openssl &lt;span class="nb"&gt;base64&lt;/span&gt; &lt;span class="nt"&gt;-A&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
  &lt;span class="c"&gt;# based the key above to generate the **extension id**&lt;/span&gt;
  &lt;span class="nv"&gt;ret&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;openssl rsa &lt;span class="nt"&gt;-in&lt;/span&gt; ./extensions/key.pem &lt;span class="nt"&gt;-pubout&lt;/span&gt; &lt;span class="nt"&gt;-outform&lt;/span&gt; DER | shasum &lt;span class="nt"&gt;-a&lt;/span&gt; 256 | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-c32&lt;/span&gt; | &lt;span class="nb"&gt;tr &lt;/span&gt;0-9a-f a-p&lt;span class="si"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Not only the popup.html but how extensions interacting with web pages is also the test target. One important function of our web extension is to change its icon if a user is visiting our partners' website. In the beginning, I was trying the &lt;a href="https://developer.chrome.com/extensions/messaging"&gt;Message Passing&lt;/a&gt; to sync up testing data between web extension and web pages. I found that I need to change codes a lot in the extensions especially for the &lt;a href="https://developer.chrome.com/apps/runtime#event-onMessage"&gt;onMessage&lt;/a&gt; and &lt;a href="https://developer.chrome.com/apps/runtime#event-onMessageExternal"&gt;onExtenalMesasge&lt;/a&gt; parts. To minimize the changes, I then used the Firebase as the medium to sync up the testing data. This probably is not the best choice but it really works for us currently.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="nx"&gt;firebase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;initializeApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="nx"&gt;firebaseDB&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;firebase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;database&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="nx"&gt;firebaseDB&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;urlPatternTest/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;update&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;testKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;icon&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;ts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nx"&gt;getTime&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The rest is about codes how we doing UI automation tests like switching tab,  login/logout and etc.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;async function selectTab(page, tabName) {
  const selector = 'div#buttonBox :first-child'; // querySelector
  let handle = await page.waitForSelector(selector); // blokc until the expected dom element loaded
  const text = await page.evaluate(sel =&amp;gt; document.querySelector(sel).innerText, selector, handle); // evalute the selector and return the data
  if (text === tabName) {
    handle = await page.$(selector);
    await handle.click();
  } else {
    handle = await page.$('div#buttonBox :last-child');
    await handle.click();
  }
}
...
....
  let selector = 'input[type="email"]';
  await sgPage.waitForSelector(selector);
  const emailHandle = await sgPage.$(selector);
  await emailHandle.type(USER_EMAIL); // key in user email

  selector = 'input[type="password"]';
  const pwdHandle = await sgPage.$(selector);
  if (_.isNil(pwdHandle)) throw new TypeError('found no password input element!');
  await pwdHandle.type(USER_PWD); // key in use pwd
...

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

&lt;/div&gt;



&lt;p&gt;I really enjoy using Puppeteer so far since its simplicity getting UI test done with its full-fledged APIs and ways of intercepting data (HTML, image, URL, cookies and etc). Right now, we are still working on the project by adding more sophisticated test scenarios. Not sure if you will use Puppeteer in the near future. Any comments are so welcome!&lt;/p&gt;

</description>
      <category>automation</category>
      <category>test</category>
      <category>puppeteer</category>
    </item>
    <item>
      <title>The Twelve-Factor App</title>
      <dc:creator>Guo-Guang</dc:creator>
      <pubDate>Fri, 18 May 2018 09:55:48 +0000</pubDate>
      <link>https://forem.com/taitung/the-twelve-factor-app-1ag4</link>
      <guid>https://forem.com/taitung/the-twelve-factor-app-1ag4</guid>
      <description>&lt;p&gt;Just read this article &lt;a href="https://12factor.net"&gt;https://12factor.net&lt;/a&gt; and found out dev.to has a series of podcast on 12factor. I will manage to listen to podcast. While reading, I am also checking how many factors I have applied completely, partially, or even none on projects I have involved. Surprisingly, all these 12 factors, in my opinion, can be shown on projects. However, it is just the matter of how much we enforce each factor in projects. &lt;/p&gt;

&lt;p&gt;Taking the codebase factor. We have tried to follow microservices architecture    to organize projects. However, I still can see the duplicated functions or codes among projects. The bad thing about the duplications is that some of functions or APIs provided by a service are under very low utilization for any reasons, which are still maintained by developers. However, you cannot directly remove those functions from a service since there could be some coupling inside.&lt;/p&gt;

&lt;p&gt;Another factor I think we can enhance is to minimize the deployment difference for dev, staging, QA, and PROD, which is Dev/prod parity factor. The problem we are facing in this factor is that the app must detect environment the app exists and then get or load proper configuration values to complete the app initialisation. This detection adds extras a bit meaningless test codes like mocking staging, or QA environments.&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>microservices</category>
      <category>deployment</category>
    </item>
    <item>
      <title>how to correctly identify a web page?</title>
      <dc:creator>Guo-Guang</dc:creator>
      <pubDate>Fri, 11 May 2018 10:01:06 +0000</pubDate>
      <link>https://forem.com/taitung/how-to-correctly-identify-a-web-page-1i38</link>
      <guid>https://forem.com/taitung/how-to-correctly-identify-a-web-page-1i38</guid>
      <description>&lt;p&gt;why need to identify a certain page? A Google browser extension needs to react to a certain page loaded from a website. The current way of identifying the specific page is to match its URL by using a regular expression generated according to a set of ULRs given by Ops people. &lt;/p&gt;

&lt;p&gt;Using regex has some drawbacks. Ops or marketing people don't know regex. Therefore, it always relies on engineers to generate the regex if there are contracts signed with partners. We are in EC field and it is at least thousands of partners in each country running our services. So far we run our service in 7 countries. &lt;/p&gt;

&lt;p&gt;Instead of using regex, I am thinking if I could use Solr or ElasticSearch to index the URL with different weights on the specific terms in the URLs. Hope to learn from how you probably address such a problem.&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Please recommend a restful API framework in Golang</title>
      <dc:creator>Guo-Guang</dc:creator>
      <pubDate>Wed, 02 May 2018 05:45:55 +0000</pubDate>
      <link>https://forem.com/taitung/please-recommend-a-restful-api-framework-in-golang-1pjf</link>
      <guid>https://forem.com/taitung/please-recommend-a-restful-api-framework-in-golang-1pjf</guid>
      <description></description>
      <category>go</category>
      <category>discuss</category>
    </item>
  </channel>
</rss>
