A Really Simple Star Rating Input in React

One of our current projects has come with a few interesting UI designs, some can turn out to be quite complex but this was possibly one of the simplest yet. Looking online there are a few packages that can do this but it soon became clear that it might be much quicker to just write a lightweight component to do just what was needed.

rendered_start_rating.png

tl;dr here’s the gist for the Star Rating React Component on Github …or you can play about with the Star Rating React Component on CodePen

 

Now, this could be expanded in lots of ways but this star rating component needed to fit the following specification;

  • The stars should toggle on or off when clicked
    • We’re not interested in half-star ratings…
  • The stars should fill up as you hover over them
  • The stars should use the defined theme colours

That last requirement meant that the component used the themeContext to allow the colour to be set by the rest of the application; however for simplicity here, the color style is applied inline. Of course, it could also be passed in as a prop.

 

The Constructor

State for this component is pretty straight forward, it keeps a track of the rating and where the user is hovering in order to render the stars correctly. The whole component may even be possible as a function using react hooks.

The stars themselves are just Unicode characters, you could make them anything you like (the empty 🖤 and full heart ❤️ emojis for example).

hearts

The score can be provided as a prop called outOf otherwise it defaults to 5 and is used to build up an int array to map later in our the render function.

    constructor(props) {
        super(props);

        this.state = {
            stars: [],
            rating: 0,
            hovered: 0,
            selectedIcon: "★",
            deselectedIcon: "☆"
        };

        let outOf = props.outOf ? props.outOf : 5;

        for (var i = 0; i < outOf; i++) {
            this.state.stars.push(i + 1);
        }
    }

Change Rating and Hover Rating

Next we need a couple of functions When a star is clicked, we set the rating in state and we look for an onChange prop to pass the new rating to. Additionally, because we want the icon to change when we are hovering over the star, we also set the rating that is currently being hovered over.

changeRating(newRating) {
        this.setState({
            rating: newRating
        });

        if (this.props.onChange)
            this.props.onChange(newRating);
    }

    hoverRating(rating) {
        this.setState({
            hovered: rating
        });
    }

Render

Finally, in the render function, we use a div wrapper to apply some inline styling. In our application, we use themeContext to set the sizing and colours however here we just specify the fontSize and color. Inside this, we map the stars array we built in our constructor to render a span element for each star. The onClick calls our changeRating function passing in the number of the star. The onMouseEnter and onMouseLeave props simply toggle the hoverRating function.

Lastly, using some conditional statements we can check if the rating and the currently hovered rating to decide whether to show the filled or empty icon for each star in the array.

    render() {

        const { stars, rating, hovered, 
                deselectedIcon, selectedIcon } = this.state;

        return (
            
{stars.map(star => { return ( { this.changeRating(star); }} onMouseEnter={() => { this.hoverRating(star); }} onMouseLeave={() => { this.hoverRating(0); }} > {rating ); })}
</div> ); }

And that’s everything you need!

Like I said, this does the job but it is by no means the most comprehensive option; if you need more options you could expand on this or look at something like react-rating which does handle things like half-star ratings out of the box.

Testing in .net Core with xUnit

I’ve recently been getting my head around some new technologies that we were looking to use in an upcoming project. With a chance to work with the .Net Core framework as part of this, I wanted to look at unit testing frameworks to see what worked well. I’m familiar with MSTest in the .Net space but there’s been a shift towards xUnit as an alternative.

 

What is xUnit?

Simply put, xUnit is another unit testing tool. What makes it different, according to its description on GitHub, is that it is free, open source and community-focused, written by the creator of NUnit v2 (another well-established testing framework).xunit.net-150px

There are two types of test in xUnit and they are identified by the attributes ‘Fact’ and ‘Theory’ rather than ‘Test’ as you might expect in other frameworks. A fact is a test that is always true, the conditions around the test do not change. A theory on the other hand, is true for a given set of data and unlike the fact tests we pass this data into the test. I’ll look at theory tests later when we talk about data-driven testing but to begin with I’ll start simple.

 

Simple Time Manager

To play with xUnit I needed a .Net Core application to test so, using Visual Studio, I made the simplest thing I could think of; a C# console app that lets you create tasks and work on them. Under the guise of being a zero-distraction productivity tool in the command line, it’s a minimum viable product so I could focus on testing. This article will be based on tests I wrote for this, so it’ll be helpful to look at the project files on GitHub.

 

Let’s Start Testing

First we want a new project for our tests so in the solution, I add an ‘xUnit Test Project (.Net Core)’ giving it a sensible name (the name of the project you’re testing with .Tests appended is a good convention).adding-an-xunit-test-project-e1530268183929.png

This creates our test project, includes dependencies for xUnit and creates the first unit test class for us. In that class is an empty test method using the ‘Fact’ attribute we talked about. This is everything we need to create our first test.

using System;
using Xunit;

namespace SimpleTimeManager.Tests
{
    public class UnitTest1
    {
        [Fact]
        public void Test1()
        {

        }
    }
}

I want to test the SimpleTask class so in the interest of readability I start by renaming this test class to ‘SimpleTaskShould’. Following the Arrange Act Assert methodology makes for clear tests that are easy to understand so we will take that approach. The arrange step for my tests will mostly be the same as they focus around a SimpleTask object which I will want to create for each test.

Rather than including it at the start of each test method I can use the class constructor to create a new instance of the SimpleTask class. Because the constructor is called for each test, this makes the SimpleTask available to all the tests in my SimpleTimeManager.Tests class without duplicating code.

My first test just checks that my new task has the correct default properties. There’s no need to perform an action and the only arrange needed (creating a new SimpleTask) happens in the constructor. That just leaves the asserts – I’m checking that the properties on my new SimpleTask match what I expect them to be

 

    public class SimpleTaskShould
    {
        private readonly SimpleTask _task;
        public SimpleTaskShould()
        {       
            _task = new SimpleTask("Sample Task");
        }

        [Fact]
        public void GetCreatedWithDefaults()
        {
            Assert.Equal(TaskState.Open, _task.State);
            Assert.Equal(TaskStatus.NotStarted, _task.Status);
            Assert.Equal("Sample Task", _task.Name);
            Assert.Equal(new TimeSpan(), _task.Duration);
            Assert.Empty(_task.AuditTracker);
        }
   }

 

Asserts

So what is happening in this test? xUnit, like other test frameworks, provides an ‘Assert’ class which provides many methods for checking the things you want to test. Here I’m using the Equal method which takes an ‘expected result’ and ‘actual result’ parameter and compares them. If they are equal, the assert passes; if they are not, the test will fail. In addition to Equal, there is NotEqual which as you might expect, checks for the opposite condition.

I also use Empty which is an Assert for collections. My SimpleTask class has an AuditTracker property which is a collection used to track whenever a change is made to the task. As this is a brand new task that we haven’t acted on, the tracker should be empty. Again, we could also use NotEmpty – in fact most of the Assert methods come in that positive/negative variant; True/False, Null/NotNull, Contains/DoesNotContain etc.

There are several other Assert methods, some you can see used in this project but for a fully exhaustive list you should look at the xUnit documentation with handy comparisons if you are coming from another test framework like I was.

Now, if we right-click inside the test class we can run the test (the  Ctrl+R, T shortcut, this comes in handy when you have more tests to run). The results appear in the Test Explorer window in visual studio. If you don’t see Test Explorer you can use the Ctrl+E, T shortcut or go to Test > Windows > Test Explorer in the Visual Studio toolbar.

naming-convention-readability.png

Traits

You can see now why we named the test class and test method; the added readability in the test output. Whether using Test Explorer like we are here, or using the dotnet command line test runner, we can now clearly see what the test is for “SimpleTaskShould.GetCreatedWithDefaults”. You’ll notice something else too, our test is part of a ‘Category’ called TaskWorkflow. How did we do that?

Another attribute in xUnit is called Trait – this is a way to organise our tests into groups, again for readability but also because it means we can run all tests with a specific trait together. The syntax is straight-forward, you use the Trait attribute and pass in the name of a trait and the value you want to apply. In my example, my trait is called ‘Category’ and I want my SimpleTask tests to be a part of the ‘Task Workflow’ category. I could apply the Trait to each test like this;

    [Fact]
    [Trait("Category", "TaskWorkflow")]
    public void GetCreatedWithDefaults()
    {

 

But because all my tests in the class are part of this category, instead I can set it at the class level and have it apply to each test method in the class

    [Trait("Category", "TaskWorkflow")]
    public class SimpleTaskShould
    {

As you might have guessed, I can apply this Trait to tests in other Test Classes too – this is a great way of grouping tests together based on functionality whilst keeping your test classes themselves focused on their respective application class.

 

Skipping Tests

Generally, I find skipping is a bad practise – if it’s a broken test you should fix it and if it’s no longer necessary you should just remove it. If you’re looking for good test coverage, a skipped test is as good as no test at all.

That said, you might want to temporarily skip a test and xUnit has a simple way to do this. In the test attribute, you provide the skip parameter with a reason;

        [Fact(Skip ="This is an example skip reason")]

Then when the tests run, you can see the reason given in the output of the test

Skipping Tests

Adding Test Output

Although I don’t skip any tests in my project, I do make use of the standard output in the test results window. It’s a good way to make the tests slightly more verbose which, for larger tests, can really assist with debugging if that test starts to fail.

xUnit provides an Abstractions namespace that needs adding to the project to make use of the ‘ITestOutputHelper’ interface. If we pass this interface into the constructor of our test class, xUnit will know to pass this in when the tests run.

using SimpleTimeManager.Tasks;
using SimpleTimeManager.Tests.TestData;
using System;
using Xunit;
using Xunit.Abstractions;

namespace SimpleTimeManager.Tests
{
    [Trait("Category", "TaskWorkflow")]
    public class SimpleTaskShould
    {
        private readonly SimpleTask _task;
        private readonly ITestOutputHelper _output;

        public SimpleTaskShould(ITestOutputHelper output)
        {
            _output = output;
            _task = new SimpleTask("Sample Task");
            _output.WriteLine(string.Format("Created a simple task called : \"{0}\"", _task.Name));

            _output.WriteLine("Leaving constructor - starting test");
        }
    }
}

My tests are all fairly small but I wanted to add some output from the Test Class constructor, where we create the new SimpleTask. This is mainly a demonstration of the ITestOutputHelper interface and also as a good way to show that the constructor is called before each test. In the code you can see that the ITestOutputHelper interface defines a WriteLine property (not dissimilar to Console.WriteLine you may be familiar with from C# Console Apps).

Now if we look at the test output for any of our test methods we see the output from our constructor;

Test Output

Data Driven Testing

So we’re familiar with the basics but one of the more interesting features that xUnit brings to the table is the Theory test method we talked about earlier. Where a Fact runs a single test, a Theory runs the same test multiple times passing in a different set of data each time. This is a great way to reduce code duplication as you don’t need to write the same test for each data set.

 

Inline Data Attributes

There’s a few ways to provide the data set for a Theory test but the easiest way is using the InlineData attribute. InlineData takes an object array as a parameter meaning that it will accept any data types you want to pass in. Then you add those parameters to the test method. I only pass in a single parameter to this test but because it accepts an array you can pass in multiple and include multiple parameters in the test method.

        [Theory]
        [InlineData(TaskState.Open)]
        [InlineData(TaskState.Closed)]
        public void ReturnTasksForRequestedState(TaskState state)
        {
            var requestedTasks = _sampletasklist.GetTasks(state);

            int expectedTaskCount = _sampletasklist.Tasks.Where(x => x.State == state).Count();

            Assert.Equal(expectedTaskCount, requestedTasks.Count());
        }

Because this test has two Inline Data attributes, it will run twice – once for each state in the TaskState enum. We can see this clearly in Test Explorer when we run this test

InlineData Tests

When we dig into the test result we see that it did run twice and that a different state was passed in each time and the test passed for both scenarios.

Custom Data Attributes

InlineData is great for a small number of variations but soon becomes unwieldy if you need to provide more than just a few datasets. It also doesn’t allow you to share your datasets between tests and test classes; you must specify them against every test. Finally, it limits where the data can come from, here we’re passing a static set of data but what if we wanted to pull our test data sets from json data or a database?

To get around this there are a few ways to share data for Theory tests but the implementation I found gave the cleanest looking code was to use custom data attributes. To create a custom attribute we need to create a class that inherits from xUnit’s DataAttribute class. This is part of the xUnit.Sdk namespace so we also need a using statement for that.

Implementing DataAttribute

The last bit we need to do, as intellisense politely informs us, is to implement the abstract member from the DataAttribute class we’re inheriting from. The GetData method is what xUnit will call when passing data into our Theory tests.

The return type of GetData is IEnumerable; xUnit will iterate over it for each test, so inside this method we use a yield return for each set of data we want to test against

    public class TaskIndexTestDataAttribute : DataAttribute
    {
        public override IEnumerable<object[]> GetData(MethodInfo testMethod)
        {
            yield return new object[] { 0 };
            yield return new object[] { 1 };
            yield return new object[] { 2 };
            yield return new object[] { 3 };
            yield return new object[] { 4 };
            yield return new object[] { 5 };
            yield return new object[] { 6 };
            yield return new object[] { 7 };
            yield return new object[] { 8 };
            yield return new object[] { 9 };
            yield return new object[] { 10 };
            yield return new object[] { 11 };
        }
    }

That’s it – now instead of having a lots of InlineData boilerplate in our code we can reuse a single attribute;

        [Theory]
        [TaskIndexTestData]
        public void ReturnRequestedTask(int taskIndex)
        {
            var requestedTask = _sampletasklist.GetTask(taskIndex);
            var taskNameNumber = taskIndex + 1;

            Assert.Equal("Sample Task " + taskNameNumber, requestedTask.Name);
        }

 

And produce a set of test results on each Theory test we apply it to

CustomData Tests

Learn More

There’s plenty more you can do in xUnit, I’m just scratching the surface here but it was a good starting point and I hope you find it useful. I was able to produce 60+ tests for this tiny application in a short amount time. If you want to see more of the areas we talked about here, take a look at those test project files; as I mentioned at the start – the application and tests are on my GitHub. For everything else, check out the documentation for xUnit.

Coding the Feynman Technique

This is what I hope should be a growing blog post as I create a starting point for turning the Feynman technique into a usable and reusable piece of software. It’s something I have been thinking of multiple applications for but ultimately all rely on the same core functionality.

What is the Feynman Technique?

Essentially it is a mental model based on the technique used by Richard Feynman to learn, understand and remember concepts quickly and comprehensively. I was drawn to it by this post which will give a better description but I mainly want to focus on the defining steps of the technique; those which I will replicate in code.

Step 1 – Naming the Concept

Quite simply the title that covers a subject you want to delve into. This just acts as the starting point for the process but also puts some boundary in place to control the scope of the problem or concept.

Step 2 – Explain the Concept

Starting with just the information you know already, try to start explaining the concept in as much detail as possible to highlight your current understanding but also, and most importantly, begin to reveal things about the subject that you don’t know.

Step 3 – Review the Gaps

Using the explanation, pinpoint the areas that are unknown and begin a focused effort on learning about those things through research and using the same process as step 2, write an explanation of these areas with as much detail as possible

Step 4 – Simplify the Language

This step reminds me of a quote by Albert Einstein; “If you can’t explain it simply, you don’t understand it well enough”.

Now that your explanation covers the topic entirely, to check that you truly understand it; go back through the explanation and simplify the language so that it is written clearly and define any larger terms or jargon using analogy where possible.

Modelling this with software

Using these steps I aim to create in software something that allows for modelling the initial concept; organising it into sub categories and a set of defined terminology. Moreover, the software should be able to link terms to their definitions where one has been provided and highlight terms that have not yet been explained. When completed, we will have created a clean and organised network of data between the concepts subcategories and the defined terms that explain them.

 

Fast, Scripted Access to Encrypted Volumes using Dropbox and VeraCrypt

So I finally decided to move everything to the cloud and use Dropbox pretty much exclusively for all my data. The problem is I still wanted an extra layer of security for confidential information; password management, banking, insurance and personal identification in the event of Dropbox having a serious security breach or someone hacking into my account.

For this I wanted to use VeraCrypt as a portable install along with the encrypted volume and store both within Dropbox so they could be accessed anywhere. Theres already great how-to guides on setting up a VeraCrypt container if you need help getting started.

Just remember not to make your volume too large. When the volume is unmounted, it will look like a single file to Dropbox so any changes will cause the entire file to be synchronised which could take some time. For the types of files I wanted to store it probably doesn’t need to be larger than a few hundred MBs. If you need more than this, it might be sensible to repeat this process and create separate VeraCrypt containers for the different types of document you need to protect.

Faster Access to your Container

We could easily stop here but for me, the process of using VeraCrypt to access the volume is a bit long winded. I wanted to just double click and enter my password without worrying about locating the container and manually mounting the drive.

Thankfully VeraCrypt comes with a great command line interface which meant I could essentially script the entire process with fairly minimal effort.  I decided to make a small batch file that could also live within Dropbox;

@echo off
set volume=\Secure
set mountDrive=X
set target=%cd%%volume%

mode con cols=50 lines=1
cd Vera
IF EXIST %mountDrive%:\ (GOTO dismount) ELSE (GOTO mount)

:mount
title Target: %volume%
color 0A
set "psCommand=powershell -Command "$pword = read-host '[  Mount  ] Password' -AsSecureString ; ^
    $BSTR=[System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($pword); ^
        [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)""
for /f "usebackq delims=" %%p in (`%psCommand%`) do set password=%%p
veracrypt /q /s /v %target% /l %mountDrive% /a /p %password% /e /b
cls
color 0E
echo|set /P=[ Mounting ] Please Wait...

:while
IF EXIST %mountDrive%:\ (GOTO dismount) ELSE (GOTO while)

:dismount
cls
title Mounted: %volume% [%mountDrive%:]
color 0C
set /P exitCode= [Dismount] Press Enter
veracrypt /q /s /d %mountDrive%

cls
(GOTO mount)

After saving this with a .bat extension in Dropbox along side the container and VeraCrypt Portable I had what I needed; double click this file, enter a password and the volume opens straight up.

But wait, what’s going on here? Let’s break it down bit by bit to explain what we’re doing and why.

Selecting the Container and Volume Letter

After turning off echo, we start by setting up a few variables for the file we want to mount and the drive letter we want it to use. 

volume is the name of the VeraCrypt container we created earlier. I called mine ‘Secure’ so we set this to \Secure

mountDrive is the drive letter we want to mount to. I’m hardcoding this, theoretically you could do something to find an available letter but X is usually available and keeps things nice and simple.

target is the full path to the veracrypt volume file. Here the file is in the same directory as the batch file so I can use %cd% to use the current directory and then use %volume% to add the file name to this path. E.g. ‘C:\Users\Eric\Dropbox\Secure’

Creating a really compact UI

Your options are limited with scripts but you can do a few things to make using it a bit more pleasant. For batch files, mode con to control the window size and the color command can add some more visual context. Additionally title allows you to change the title of the window itself; I’m using this so we can keep the actual window really discrete and still show what the script is currently doing. The cls command just clears the console window to keep things tidy between the stages.

Checking the current state

Next we use cd to change to the folder containing our portable VeraCrypt software, for me, this is in the same location inside a folder called ‘Vera’. Then, just to be sure the drive isn’t already mounted, we want to check for the existence of our drive letter. Based on this, we want to go to either the :mount or :dismount section of the script.

Mounting the Volume

I set the window title and use green text to signal that we are going to mount the volume. Now, we need to provide the password in the command to VeraCrypt but by default, if we type this into our command window, it will appear on the screen in plain text. As with any password, we want to hide our input. To do this I’m using a bit of PowerShell wizardry courtesy of StackOverflow. Then, it’s simply a case of calling our VeraCrypt install with some command line options to tell it how to mount the volume.

Mount

/q /s runs VeraCrypt with no prompts or error messages and only keeps the application open long enough to complete the command.

/v is our volume and /l is the drive letter we want to mount to so we pass in the target and mountDrive variables respectively.

/a automatically mounts the volume and /p is for the password we need to decrypt it so we pass in our password variable.

finally /e opens the volume in an explorer window and /b causes a system beep to confirm the command completed. You can leave either/both of these off if you want to keep the process completely silent.

A full list of command line options can be found in their Command Line Usage Documentation.

After this, there is a short while loop that waits for the volume to be properly mounted before giving you the option to dismount it again.

Mounting

Dismounting the Volume

The dismount is really simple, all we are doing here is using set for a variable called exitCode. This doesn’t get used for anything but is an alternative to the pause command and, unlike pause, doesn’t put the cursor on to a new line; this pushes the text up and would mean our window height would need to be another line taller just to compensate for it. (you may have noticed we used it with ‘echo’ further up to achieve the same effect)

Dismount

Then we call VeraCrypt again with the same /q /s we saw before but this time using /d and passing in our mountDrive to dismount the volume

For future improvement
  • Instead of just hard-coding the drive letter for mounting the volume, it would be better to find an available letter in case the one we wanted to use is already taken.
  • To get around the limits of Dropbox and volume sizes, it would be good to have this handle multiple volumes, even if they all used the same password. Either that or, based on the provided password, only the correct volumes would mount
  • It would be great to extend the portable applications to have a MacOS and Linux version of VeraCrypt and then use a similar script for those operating systems to make it easier to access the protected volume from more devices.