Automated JS unit testing in VS Code

I love using VS Code, and i want to be more diligent about unit testing especially with JavaScript. There didn’t seem to be an obvious way to do this in VS Code, so I cobbled together a few resources that ended up working well. It does require you have node.js installed on your machine first, so get that then proceed.

By the way, for those of you familiar with unit testing this may seem remedial and possibly outdated. It’s new to me, and I don’t want to forget how I did this, so feel free to leave comments and contribute to me and other newcomers to JS unit testing what works for you and what you suggest should be done differently.

There are plenty of test suites and task runners, choose what works best for you. The key takeaway is we need a test suite and a task runner of some kind. For this I’m using QUnit and Karma.

With VS Code open to your project folder, open the terminal and run the following commands:

npm install karma –save-dev
npm install karma-qunit karma-phantomjs-launcher –save-dev
npm install -g karma-cli
npm install –save-dev qunitjs

Once those are done installing configure karma by running this command:

karma init karma.conf.js

Follow the prompts to configure how it will run. For automated testing ensure you answer “Yes” when it asks if you want to re-run tests when a file changes. It’s not like WebStorm where it waits a few seconds, sees no activity, auto-saves then runs the tests, but it will autorun if you save the file. Once finished run this command to launch the task runner:

karma start

That’s it, now when you write your JS tests they will autorun and display in the terminal whenever you save changes. Of course, you can also open the browser to your html file you make when building your tests, such as with QUnit. There are other browsers you can use as well, including PhantomJS for headless browser testing. Let me know what works for you!

My latest project – SLRPi

Those of you who know me know in my spare time I write code, build solutions for things, etc. I like having a few “pokers in the fire” as the saying goes so I can bounce from side project to side project in case I get stonewalled and need a break. I’ve had a Raspberry Pi 2 Model B board laying around for a couple of years and couldn’t decide what to build with it. Many ideas crossed my mind but nothing stuck…until this past week.

Another side interest of mine has always been Astronomy. Back in 1999 I joined a project at UC Berkeley called SETI (Search for Extra-Terrestrial Intelligence). Part of their project included a grid-computing effort that would process information from radio telescopes around the world and look for narrow-band signals, which amidst the regular noise of space waves are not known to be produced naturally. The machines on the grid-computing side would process the results and send them back to UCB for review. Several years after the project took off there was discussion about the SETI program losing funding and shutting down, so I stopped participating. Just recently the thought occurred to me…perfect use for the RPi!

This spawned the idea of SLRPi – SETI Listener for Raspberry Pi. Sure the Seti@Home folks have an application for just about any platform you can install on your desktop or mobile device and participate, but I wanted my challenge to be to start from a blank Debian environment and build it from the ground up. No installers, no easy packages, just raw development from scratch.

I started out with a clean install of Debian Jessie (Full) on a 32GB SD card. After extracting the OS onto the card using Etcher I began by first configuring the wireless adapter I bought for it to allow me to work without being physically connected to my router. It’s an EDIMax EW-7811UN WiFi Adapter, and configuration was quite simple.

First I edited /etc/network/interfaces like so:

auto lo
iface lo inet loopback
iface eth0 inet dhcp

allow-hotplug wlan0
auto wlan0

iface wlan0 inet dhcp
     wpa-ssid="SSID"
     wpa-psk PASSPHRASE #note this is not your password, it is the result of running wpa_passphrase SSID PWD at the command line!

This allows both the ethernet port (RJ-45) on the board as well as the wireless adapter. Then I could either reboot the device or enter the following to cycle the network service:

sudo ifdown wlan0

sudo ifup wlan0

Once connected to the wireless network, I could now run updates on the OS to make sure I had the latest of everything. To do this I ran the following:

sudo apt-get update

sudo apt-get dist-upgrade

The next issue to tackle is the known issue of wireless adapters “going to sleep” or suffering from intermittent connectivity. A couple of things had to be modified to ensure a consistent connection. First, I edited /etc/modprobe.d/8192cu.conf:

options 8192cu rtw_power_mgnt=0 rtw_enusbss=0

Then I created a script that will be scheduled to run in crontab every 5 minutes that ensures the network stays alive on the device. First, I created a script at /root/wifi_recover.sh:

keepalive_host="192.168.1.1"
ping -q -c1 $keepalive_host >> /dev/null

if [ "$?" -ne "0"]; then
	echo "`date` WIFI DOWN" >> wifi_log.txt
	ifdown wlan0
	rmod 8192cu
	modprobe 8192cu
	ifup wlan0
	echo "`date` WIFI UP" >> wifi_log.txt
fi

Then I ran crontab -e and added the following two entries:

*/1 * * * * ping -c 192.168.1.1
*/5 * * * * /root/wifi_recover.sh

This tells the OS to ping my router every minute and to run the script every 5 minutes. With the wireless network now up, running and stable I wanted to configure my 4″ Waveshare Spotpear screen I bought for it so I could use that instead of carrying around a spare monitor. Sure I can SSH into the terminal from my laptop, but where’s the challenge in that? Setting up the LCD screen was a bit more complicated in versions of Debian prior to Jessie. It required downloading Waveshare’s Github repo (notro) and installing that, then configuring /etc/modules, /boot/cmdline.txt, /usr/share/X11/xorg.conf.d/99-fbturbo.conf, /boot/config.txt and /usr/share/X11/xorg.conf.d/99-calibration.conf. Thanks to the latest release of Debian Jessie this type of screen is accommodated as part of the OS! Installing the drivers was the only thing needed.

To configure the screen, first I had to enable SPI in raspi-config, allowing the on-board connectors to support video (as opposed to the HDMI port). I then ran the following command:

wget "http://www.waveshare.com/w/upload/7/74/LCD-show-170309.tar.gz"

This will download the drivers needed to support the LCD screen. Once the download finished, I ran the following command to expand the tar file:

tar xvf LCD-show-*.tar.gz

Once finished, I switched directories to the LCD-show/ directory and ran the following to make the LCD4-show file executable:

chmod +x LCD4-show

Finally, to enable the showing of the 4″ screen I ran this:

./LCD4-show

Now, after a reboot the screen came up and I was able to have a truly portable dev environment!


The next task was to configure the device to connect to the SETI@Home project and process tasks. Yes there’s an installer to do this for you, but again…where’s the challenge? Instead I navigated to my /home/pi/Desktop path, created a directory called “BOINC” and grabbed the package from the SETI site (x86 Linux) using the following:

cd /home/pi/Desktop
md BOINC
cd /BOINC
wget "https://boinc.berkeley.edu/dl/boinc_7.2.42_i686-pc-linux-gnu.sh"

I ran this script file, which created all of the directories and content I needed. Then I needed to start configuring the BOINC client. First, I modified the global preferences in /var/lib/boinc-client/global_prefs_override.xml file like so:

<global_preferences>
   <run_on_batteries>0</run_on_batteries>
   <run_if_user_active>1</run_if_user_active>
   <run_gpu_if_user_active>0</run_gpu_if_user_active>
   <suspend_cpu_usage>50.000000</suspend_cpu_usage>
   <start_hour>0.000000</start_hour>
   <end_hour>0.000000</end_hour>
   <net_start_hour>0.000000</net_start_hour>
   <net_end_hour>0.000000</net_end_hour>
   <leave_apps_in_memory>0</leave_apps_in_memory>
   <confirm_before_connecting>1</confirm_before_connecting>
   <hangup_if_dialed>0</hangup_if_dialed>
   <dont_verify_images>0</dont_verify_images>
   <work_buf_min_days>0.100000</work_buf_min_days>
   <work_buf_additional_days>0.500000</work_buf_additional_days>
   <max_ncpus_pct>100.000000</max_ncpus_pct>
   <cpu_scheduling_period_minutes>60.000000</cpu_scheduling_period_minutes>
   <disk_interval>60.000000</disk_interval>
   <disk_max_used_gb>10.000000</disk_max_used_gb>
   <disk_max_used_pct>90.000000</disk_max_used_pct>
   <disk_min_free_gb>1.500000</disk_min_free_gb>
   <vm_max_used_pct>75.000000</vm_max_used_pct>
   <ram_max_used_busy_pct>50.000000</ram_max_used_busy_pct>
   <ram_max_used_idle_pct>90.000000</ram_max_used_idle_pct>
   <max_bytes_sec_up>0.000000</max_bytes_sec_up>
   <max_bytes_sec_down>0.000000</max_bytes_sec_down>
  <cpu_usage_limit>25.000000</cpu_usage_limit>
   <daily_xfer_limit_mb>0.000000</daily_xfer_limit_mb>
   <daily_xfer_period_days>0</daily_xfer_period_days>
</global_preferences>

 

This pre-configures the BOINC client to basically run always. Note the cpu_usage_limit and suspend_cpu_usage values are set very high intentionally. If this were a PC I would be using for other purposes as well as for this activity I would adjust these accordingly. However, since this is the only thing this machine will be doing, I cranked them up to ensure it would always run.

Next I needed to connect to the project using my account. To do this I used the boinccmd command like so:

boinccmd --project_attach http://setiathome.berkeley.edu your_account_key_string

The account key is available by logging into the site and checking your account. Once that completed I started the boinc-client service:

sudo service boinc-client start

That’s it, the client was now getting information from the radio telescope, processing it and sending it back to UCB. I went ahead and further customized this installation by configuring it to run always, not suspend, etc. I also created a couple of scripts to launch the service as a daemon on reboot by adding the following to crontab:

@reboot /pathtostartupscript

The startup script looks like this:

#!/bin/bash
# SETI@Home listener script
# Run this script to report on current progress of all active projects
# and tasks
#watch -n 5 'echo "SLRPi Statistics";echo;boinccmd --get_project_status | grep $
watch -n 5 './checker'

Where “listener” is another script I wrote to basically return the current status of the project to the screen every 5 seconds. The listener script looks like this:

#!/bin/bash
# SETI@Home listener script
# Run this script to report on current progress of all active projects
# and tasks
#watch -n 5 'echo "SLRPi Statistics";echo;boinccmd --get_project_status | grep -e "user_total_credit";boinccmd --get_tasks | grep -e "fraction done"'
watch -n 5 './checker'

The “checker” script looks like this:

#!/bin/bash
boinccmd --project http://setiathome.berkeley.edu update
echo -e "SLRPi Statistics\n\n"
boinccmd --get_project_status | grep -e "user_total_credit" | while read -r line; do re="(.*)[a-zA-Z:_]+(.*)";  while [[ $line =~ $re ]];  do    line=${BASH_REMATCH[1]}${BASH_REMATCH[2]};  done;  a=$(echo "$line" | bc);  printf "Total Credit: %.2f\n" $(echo -e "scale=2\n($a)"|bc); done;
boinccmd --get_tasks | grep -e "fraction done" | while read -r line; do re="(.*)[a-zA-Z:]+(.*)";  while [[ $line =~ $re ]];  do    line=${BASH_REMATCH[1]}${BASH_REMATCH[2]};  done;  a=$(echo "$line * 100" | bc);  printf "Task completion: %.2f%%\n" $(echo -e "scale=2\n($a)"|bc); done;

This has definitely been a learning process and I’m by no means done. If you have done this already and have suggestions or comments I welcome your feedback. Thank you for reading!

6/23/2017 Update: The previous change was in fact the correct answer, the screen has been up ever since setting that value!  Now, on to the next challenge: having the client grab new tasks when the existing ones complete.  The other GUI-based clients just grab new tasks automatically, you don’t have to do anything.   For some reason the Linux command-line isn’t automatically getting new tasks.  Once I figure it out I’ll post it here.  If someone already has this answer please leave a comment!

6/21/2017 Update: I think I fixed the screen blanking issue!  I added the following to the end of /boot/cmdline.txt

consoleblank=0

So far the screen has been up longer than 10 min, where it normally blanked out at 10 min.  I’ll check back again tomorrow to see if it stays up.

6/26/2017 Update: Unfortunately, it looks like installing the Linux x86 version of the BOINC client onto a Raspberry Pi isn’t going to work.  The software is designed for an x86 architecture processor, and the Pi has an ARM proc.  Reading up on the BOINC design itself, unless you’re running v8 for Windows/Android, or a customized version for other platforms it won’t get new tasks.  This is a huge stumbling block for the RPi, but not something I’m unwilling to attempt to overcome!  Meanwhile, I installed my same scripts and code onto a Linux box in Azure just to keep the code running, also to make sure my scripts are behaving.  I’ll post here when I finish the modified ARM version of BOINC.

6/28/2017 Update: Well, good news!  I read up on the forums on the SETI@Home website, and it looks like there are several builds for RPi already working.  I had to register another account on their beta site and install another client app package from Debian, but I got it running again.  Hopefully it’ll get new tasks this time, I’ll report back here after these tasks finish up whether or not it does work.

So this time I had to uninstall (remove –purge) previous installations of boinc-client, then do the following:

sudo apt-get update
sudo apt-get install boinc
sudo apt-get install boinc-app-seti

That third install is the latest v8 build for Debian and contains the SETI@Home enhanced application. Installing this in combination with the others allows it to run and grab new tasks…so far.

Then I had to register a new account on http://setiweb.ssl.berkeley.edu/beta, and once I had the account key I could join the project on the SLRPi like so:

cd /usr/bin
boinccmd --project_attach http://setiweb.ssl.berkeley.edu/beta/ your_account_key_string

Then it was just a matter of updating my checker script to point to this new project URL and things are running well!

6/30/2017 Update: Today as existing tasks reached 90% completion it automatically grabbed 3 more! Success! Now to allow SLRPi time to process tasks from several radio telescopes and hopefully one of those will be an extra-terrestrial signal or communication of some kind.

SharePoint and the Future of InfoPath

For those who don’t already know, InfoPath’s days are numbered. Microsoft has discontinued releasing InfoPath as part of the Office suite of applications, but will be supported as part of their typical lifecycle cadence of 10 years. I know many business users of SharePoint who have used InfoPath either to create custom List Forms or custom forms for a Form Library, and I am regularly asked “will InfoPath be supported in SharePoint 2016?”. My response is usually “Yes, it will be supported”, but in reality business users should be aware of the changes forthcoming, at least as of the date of this post.

While watching the SharePoint Virtual Summit today several chat dialogs took place between Microsoft staff and attendees, many involving this same topic. I captured what I could and wanted to share it here. The responses to the questions below are from Microsoft staff. Please feel free to comment if you have additional or corrective knowledge about SharePoint and InfoPath you’d like to share as well. Much of this is coming in Feature Pack 2 for SharePoint 2016 (coming Fall 2017).

In summary, InfoPath is still supported and can be used against any SharePoint list or library, but it’s not going to be directly integrated into the UX.

Is there any information available on the proposed replacements for InfoPath and SharePoint Designer?

PowerApps and Flow will be replacing custom forms and workflow design. PowerApps on SharePoint lists is our going forward solution to succeed many classic InfoPath scenarios. It’s the new solution for custom forms in SharePoint.

Will PowerApps fully succeed Infopath forms, or will they co-exist?

Depends on the scenario – PowerApps will enable custom forms in SharePoint, support simpler configuration etc. all of which InfoPath users love using. Watch out for blog posts and Microsoft Mechanics videos.

Can you integrate PowerApps forms with REST services? Just like how you could in InfoPath or custom JavaScript forms?

Yes, we call them custom connectors, https://powerapps.microsoft.com/en-us/tutorials/register-custom-api/

What will happen to any existing deployed InfoPath forms?

You will be able to create equivalent forms in PowerApps. We don’t plan to have a migration tool at this time. We have been rebuilding InfoPath forms with PowerApps to test this out. It does take a slightly different approach, but it is possible to redo most without issue.

Will there be any way or method for customers who use InfoPath currently to convert them to PowerApps without having to recreate everything manually?

This is not available at this time.

What is the path from InfoPath forms to PowerApp or something to replace?

You’ll be able to open the PowerApps designer to build new forms directly from your list – the data stays in place and the new forms just take over for SharePoint.

Populate a SharePoint 2013 PeoplePicker field using JavaScript/jQuery

Here is a quick and fairly simple way to programmatically populate a SharePoint 2013 People Picker field with a user based on their email address. This example assumes you have more than one People Picker field on the page. You will need:

  • The display name of the People Picker Field
  • The email address of the user you want to add to the People Picker Field

Add the following code to either a Script Editor Web Part (inside <script> tags) or on your page in the PlaceHolderAdditionalPageHead, also in <script> tags:

var dispTitle = "";
var pickerDiv = $("[id$='ClientPeoplePicker'][title='" + dispTitle + "']");
var peoplePicker = SPClientPeoplePicker.SPClientPeoplePickerDict[pickerDiv[0].id];
var usrObj = { 'Key': 'email@address.com'};
peoplePicker.AddUnresolvedUser(usrObj,true); 

In one case, I had to remove the “title” attribute filter from the pickerDiv var to get it to work, but it was the only People Picker on the page, so we were good.

Hope this helps!

Posts and ramblings about SharePoint, software development, and other things I thought were cool