Sunday, October 2, 2016

Creating A Fancy CSS Button

I was in a meeting at work the other day where we were discussing our interview process for front-end developers.  We were taking a step back and trying to decide what exactly we were going to look for in our interview process and if we were finding those skills in the developers we were interviewing.  During the process the thought of interviewing for CSS was brought up and we started looking into some possible interview questions and stumbled across this website.
The first one is a simple question, but was really interesting.  People in the room seemed to think it was way too hard and I wasn't 100% sure how I would do it without internet access.  Here is the question:  Using CSS properties alone, recreate this button:

So I decided to take this as a personal challenge and ended up coming pretty close to it by just eyeballing the colors, spacings, etc.  It also took me way less time than I thought it would have and I learned a few things in the process.  Here is the end result:

Breaking it down, I started with the easies things first to get me going.  So I tackled the actual text of the button as my first thing.  To get the text to appear correctly, I knew the font-family needed to be a Sans-Serif, the font weight to be a bit on the bold size, to update the text color to a dark grey instead of black, and finally to just make sure whatever text in the button is uppercase.  Here is the css to do those things:

.button {

  text-transform:uppercase;

  color:#444444;

  font-family:sans-serif;

  font-weight:bold;

  font-size: 14px;

}



The next thing I decided to tackle was the stars.  The solution to this is to use a font-family, svg, or something else with before and after selectors.  If you haven't used them before check out the article about using after and before selectors.  I decided to use font-awesome in my solution because it had a star icon and I could just reference the CDN in my jsfiddle.   If you haven't used font icons before I wrote about it previously here.  I messed with the colors a bit and ended up with some pretty simple before and after selectors.

.button::before{

   font-family: FontAwesome;

   color:#999999;

   content: "\f005";

}




.button::after{

   font-family: FontAwesome;

   color:#999999;

   content: "\f005";

}


So now that the content is correct, the next thing was to take a stab at the background and the the first border.  So I added some padding to get the spacing of the button correct, and then went to work on the background.  I knew you could have gradients in css, but I hadn't used them in a while so I didn't quite remember the syntax.  I found some examples online like this and then created a gradient to the bottom with my 2 shades of gray.  Finally I added a simple boarder and some border radius and we are starting to look pretty good now.

.button{

  margin-left:10px;

  text-transform:uppercase;

  color:#444444;

  font-family:sans-serif;

  font-weight:bold;

  font-size: 14px;

  border-radius: 5px;

  border:.5px solid #aaaaaa;

  background: linear-gradient(180deg, #eeeeee, #aaaaaa);

  padding: 10px;

}


The last thing that was needed also the thing I was least certain about.  I was sure it could be done, cause otherwise why would the ask the question?  So I looked into box-shadow to see how that could be used and found something amazing.  It can be used N number of times!  So I finally had my solution.  I just needed a few different levels of box-shadow.  I needed one really dark layer around the border, followed by the larger light gray area.  Next I added a white gap followed by the final border.  Here is the final css for the .button class.

 
.button{

  margin-left:10px;

  text-transform:uppercase;

  color:#444444;

  font-family:sans-serif;

  font-weight:bold;

  font-size: 14px;

  border-radius: 5px;

  border:.5px solid #aaaaaa;

  background: linear-gradient(180deg, #eeeeee, #aaaaaa);

  box-shadow:  0 0 1px 1px #666666,

            0 0 0 6px #dddddd,

            0 0 0 8px #ffffff,

            0 0 0 10px #888888;

  padding: 10px;

}


Cheers!




Friday, September 30, 2016

Using Enzyme To Test React Components

With new frameworks comes new ways of testing things.  With Angular 1.x there were tools such as angular-mocks that were designed to try and make your life easier and test your components and directives efficiently and effectively.  For unit testing any front end ui code the ideal scenario would be to only render that specific component, but still be able to test that the correct properties are being passed onto any children components.  The inner workings, rendering, etc. of those children components are not the concern of the parent.  The true unit test concern is making sure that all needs of the children are being through the exposed properties.  Any actual rendering of multiple components and interaction is outside the scope of an actual unit and falls into a different category of testing.  This is something that the angular-mocks framework failed to do properly and is one of the major reasons we ended up abandoning use of it.

For react there is an amazing tool called enzyme.  My favorite feature is that you can test the component without rendering the children components!  It is called shallow rendering.  I'll walk through some quick samples of why this is great and how you use it.


So to get started, let's use the CustomList object that I had in my previous post.  Here is a link to the fiddle.  The code for the CustomList is as follows, and add a click function for each template to test a function.

class CustomList extends React.Component {

    render() {

        const ItemTemplate = this.props.itemTemplate || DefaultRow;

        return (
            <ul className="list-container">
            {this.props.items.map((item) => <ItemTemplate item={item} onClick={() => this.props.onRowClick(item)} />)}

            </ul>

         );

    }

}


So what do we want to test here?  One obvious thing is to make sure that there is an item row for each item passed into the list template.  So for each item passed in there should be an item for each one.

A simple test using jasmine might look like this:

it('should have an item template for each item', () => {
    const items = [ {id: 'id1'}, {id: 'id2'}, {id: 'id3'} ];

    const onRowSelect = jasmine.createSpy('onRowSelect');

    const component = shallow(<CustomList items={items} onRowSelect={onRowSelect} />);

    expect(component.find(ItemTemplate).length).toBe(3);

});

To break it down we are creating a shallow rendering of the component using JSX and pass in whatever properties that we might have if we were using with another component.

Now we want to test the properties of a component.  So let's use the same example and say each ItemTemplate should have an appropriate item.

it('should have a corresponding item property on each ItemTemplate', () => {
    const items = [ {id: 'id1'}, {id: 'id2'}, {id: 'id3'} ];

    const onRowSelect = jasmine.createSpy('onRowSelect');

    const component = shallow(<CustomList items={items} onRowSelect={onRowSelect} />);

    component.find(ItemTemplate).forEach( (itemTemplate, index) => {

        expect(itemTemplate.prop('item')).toBe(items[index]);

    });

});


Now that we have that, we might want to test the click events of each one and make sure they are correct.  For that we can 'simulate' a DOM event that would cause the onClick event to be fired.

it('should fire an onClick event for each row with the appropriate item' , () => {
    const items = [ {id: 'id1'}, {id: 'id2'}, {id: 'id3'} ];

    const onRowSelect = jasmine.createSpy('onRowSelect');

    const component = shallow(<CustomList items={items} onRowSelect={onRowSelect} />);

    component.find(ItemTemplate).forEach( (itemTemplate, index) => {

        itemTemplate.simulate('click');

        expect(onRowSelect).toHaveBeenCalledWith(items[index]);

    });

});


And there you have some simple tests using shallow rendering.
Cheers!

Friday, September 23, 2016

React Item Templates

With the future of Angular 1.x development coming to a head, our team started looking at other front end technologies that could potentially live side by side with angular 1.x and eventually (a long time down the road) replace our angular 1.x app completely.  We considered a few frameworks and ended up settling on React.js.

Shamelessly stolen picture from work HipChat room. 

One of the problems I recently worked on required a multi selectable list of items.  The catch was that I wanted to allow the template of the item to customizable while allowing for most of the functionality to be the same.  I realized that you could pass in a function as a property, and wondered why not a react component class.  It is essentially a function.  I tried it out and it ended up working.  Here is a JSFiddle with using that idea:




So in the container class, CustomList, I accept an optional parameter called itemTemplate.  It should be a function.  I then set a variable called ItemTemplate to be either the itemTemplate passed in or the DefaultRow class.  The key thing here to note is that you must make your ItemTemplate variable name capitalized.  React has a convention that you custom elements need to be capitalized.  I can then just pass whatever properties to each item instantiation and each one can format however they like.  Super Easy!