Showing posts with label Javascript. Show all posts
Showing posts with label Javascript. Show all posts

Monday, 26 November 2018

Enzyme Cheat Sheet

Here is a reminder of the enzyme tips I've picked up so I don't forget!

Basics

Mount a react component in a test

import React from 'react'
import { mount } from 'enzyme'

describe('MyReactComponent', () => {
  const $ = mount(
     <MyReactComponent />
  )

  ...
})

Now different expectations and finds can be used to test,

A React Class
expect($.find('MyReactClass').exists()).toBe(false)

An html element
expect($.find('button').exists()).toBe(false)

An html id
expect($.find('#my-id').exists()).toBe(false)

A style
expect($.find('.some-style').exists()).toBe(false)

Html properties
expect($.find('[aria-label="Save"]').exists()).toBe(false)
expect($.find('[title="Save"]').exists()).toBe(false)

Combination - Html element & Property
expect($.find('button[title="Save"]').exists()).toBe(false)

HTML / Text / Contains

Text content.  Find the first of many 'myClass' css classes and check the text of the element
expect($.find('.myclass').text()).toContain("My Value")
expect($.find('.myclass
').text()).not.toContain("My Value")

As above but with an exact text match
expect($.find('.myclass
').text()).toBe("The exact text")
As above but getting the whole html of the element rather than just the text
expect($.find('.myclass').at(0).html()).toBe("<div>something</div>")

Focus

Focus a field with enzyme
const inputField = $.find('#myInput')
inputField.getDOMNode().focus()

Validate that a field has focus
expect(document.activeElement.id).toBe('the id expected')

Props

Find an element and get the html properties
const button = $.find('[aria-label="My Button"]')
expect(button.props().disabled).not.toBe(true)

Once an element has been found the react props can be used for expectations by also using props()
expect($.find('MyReactClass').props().options).toEqual([{option: 'option1'}, {option: 'option2'}])






Monday, 12 November 2018

Formik

Formik is a brilliant React form builder.  It is simple and intuitive.  It includes validation using a third party - I'm using yup below.

Basic Formik

This example below shows the basics of using Formik.  The internal properties and functions of formik take care of all the plumbing.  All you need to do is wire the onChange and onBlur functions to the individual 

<div>
  <Formik
    initialValues={{
      title: '',
      firstName: '',
      surname: ''
    }}
    validationSchema={Yup.object().shape({
      title: Yup.string()
        .trim()
        .required('Please enter a title')
        .max(5, 'Too many characters (Maximum 5 allowed)'),
      firstName: Yup.string()
        .trim()
        .required('Please enter a firstName')
        .max(100, 'Too many characters (Maximum 100 allowed)'),
      surname: Yup.string()
        .trim()
        .required('Please enter a surname')
        .max(100, 'Too many characters (Maximum 100 allowed)'),
      
    })}
    onSubmit={values => alert(values)}
  >
    {formikProps => {
      const {
        values,
        touched,
        errors,
        isSubmitting,
        handleChange,
        handleBlur,
        handleSubmit,
        setFieldValue,
        setFieldTouched
      } = formikProps
      return (
        <form>
          <div>
            <label htmlFor="title">
              <span className="mandatory">Title</span>
              <input
                id="title"
                type="text"
                value={values.title}
                onChange={handleChange}
                onBlur={handleBlur}
                className={`${errors.title && touched.title ? error : ''}`}
              />      
              {errors.title && touched.title && <div>{errors.title}</div>}
            </label>
          </div>

          <div>
            <label htmlFor="firstName">
              <span className="mandatory">First Name</span>
              <input
                id="firstName"
                type="text"
                value={values.firstName}
                onChange={handleChange}
                onBlur={handleBlur}
                className={`${errors.firstName && touched.firstName ? error : ''}`}
              />      
              {errors.firstName && touched.firstName && <div>{errors.firstName}</div>}
            </label>
          </div>

          <div>
            <label htmlFor="surname">
              <span className="mandatory">Surname</span>
              <input
                id="surname"
                type="text"
                value={values.surname}
                onChange={handleChange}
                onBlur={handleBlur}
                className={`${errors.surname && touched.surname ? error : ''}`}
              />      
              {errors.surname && touched.surname && <div>{errors.surname}</div>}
            </label>
          </div>
        </form>
      )
    }}
  </Formik>
</div>


Validate on Edit

By default Formik will validate once the first blur has occurred and then everytime on change.  This gives the user the chance to get the content right first without being bothered by error messages.  However, should you want to validate all changes from the off you can change your inputs to include an onInput function,


            <label htmlFor="surname">

              <span className="mandatory">Surname</span>
              <input
                id="surname"
                type="text"
                value={values.surname}

                onInput={() => setFieldTouched('surname', true)} // Validate as the user types
                onChange={handleChange}
                onBlur={handleBlur}
                className={`${errors.surname && touched.surname ? error : ''}`}
              />      
              {errors.surname && touched.surname && <div>{errors.surname}</div>}
            </label>


Validate Function

Validation doesn't have to be done by a schema.  This is quite limiting as it doesn't allow dynamic messages to be generated.  You can still use a schema as this is really easy syntax but just recreate it each time.  If you use the validate function the Formik 'values' object is passed to it.  This can be used to generate a schema with the current values and adjust the error messages accordingly.  In the example below the validate function calls for a validationSchema.  The schema uses the values and the ` string template indicator to create dynamic error messaages.

getValidateSchema = values => 
  Yup.object().shape({
    title: Yup.string()
      .trim()
      .required('Please enter a title')
      .max(5, `Too many characters (${values.title.length} entered, Maximum 5 allowed)`),
    firstName: Yup.string()
      .trim()
      .required('Please enter a firstName')
      .max(100, `Too many characters (${values.firstName.length} entered, Maximum 100 allowed)`),
    surname: Yup.string()
      .trim()
      .required('Please enter a surname')
      .max(100, `Too many characters (${values.surname.length} entered, Maximum 100 allowed)`),
  })

validate = values => {
  try {
    validateYupSchema(values, this.getValidateSchema(values), true, {})
    return {}
  } catch (error) {
    return yupToFormErrors(error)
  }
}

render = () => 
  <div>
    <Formik
      initialValues={{
        title: '',
        firstName: '',
        surname: ''
      }}
      validate={values => this.validate(values)}
      onSubmit={values => alert(values)}
    >
      {formikProps => {
        const {
          values,
          touched,
          errors,
          isSubmitting,
          handleChange,
          handleBlur,
          handleSubmit,
          setFieldValue,
          setFieldTouched
        } = formikProps
        return (
          <form>
            <div>
              <label htmlFor="title">
                <span className="mandatory">Title</span>
                <input
                  id="title"
                  type="text"
                  value={values.title}
                  onInput={() => setFieldTouched('title', true)}
                  onChange={handleChange}
                  onBlur={handleBlur}
                  className={`${errors.title && touched.title ? error : ''}`}
                />      
                {errors.title && touched.title && <div>{errors.title}</div>}
              </label>
            </div>

            <div>
              <label htmlFor="firstName">
                <span className="mandatory">First Name</span>
                <input
                  id="firstName"
                  type="text"
                  value={values.firstName}
                  onInput={() => setFieldTouched('firstName', true)}
                  onChange={handleChange}
                  onBlur={handleBlur}
                  className={`${errors.firstName && touched.firstName ? error : ''}`}
                />      
                {errors.firstName && touched.firstName && <div>{errors.firstName}</div>}
              </label>
            </div>

            <div>
              <label htmlFor="surname">
                <span className="mandatory">Surname</span>
                <input
                  id="surname"
                  type="text"
                  value={values.surname}
                  onInput={() => setFieldTouched('surname', true)}
                  onChange={handleChange}
                  onBlur={handleBlur}
                  className={`${errors.surname && touched.surname ? error : ''}`}
                />      
                {errors.surname && touched.surname && <div>{errors.surname}</div>}
              </label>
            </div>
          </form>
        )
      }}
    </Formik>
  </div>

Friday, 29 July 2016

Angular JS Directive For Decimal Places

Here is a simple example for creating an Angular JS Directive.  In this particular case the input is limited to two decimal places but other code could be created here to limit the input in other ways.

Angular Directive

The directive is in javascript and needs to be imported into the page.

(function() {
    'use strict';

    angular.module('myApp').directive('limitedDecimalPlaces',['$filter', function ($filter) {
    return {
        require: 'ngModel',
        link: function (scope, element, attr, ngModelCtrl) {

            if (!ngModelCtrl) return;

            function round(value)
            {
                return Math.floor(value * 100) / 100;
            }

            ngModelCtrl.$parsers.push(function (value) {
            var cleanValue = value;
                if (value != value.toFixed(2))
                {
                    cleanValue = (value) ? round(value) : value;
                    ngModelCtrl.$setViewValue(cleanValue.toString());
                    ngModelCtrl.$render();
                }
                return cleanValue;
            });
        }
    };
}]);
})();

The ngModelCtrl is the model controller for this angular input.
$parsers is an array of the parsers that are applied to this input.  $parsers.push adds the function to the array (push is a standard Arrays.push() javascript function)

ngModelCtrl.$setViewValue(...) sets the value into the view part and must be a string.  Overall the function rounds the number to two decimal places if necessary and assigns it to the cleanValue.  This is then set into the view and returned so that the model is updated.  Whatever is returned from this function is what is set into the model.

Usage

The standard input can have this directive added to it so that the validation is wired into the input.

    <input type="number" name="myNumber" ng-model="myNumber" limited-decimal-places>

Tuesday, 30 October 2012

Spring and JSON

The integration between Spring and JSON objects is very strong and can be incredibly useful from a client web app.

Spring Setup

Spring requires very little setup.  Provided the Jackson classes are on the classpath

    <dependency>
        <groupId>org.codehaus.jackson</groupId>
        <artifactId>jackson-mapper-asl</artifactId>
        <version>1.9.7</version>
        <scope>compile</scope>
    </dependency>

Then spring is basically ready to go!

Returning JSON

Returning JSON to the client is the easiest part. Just return a class or list of classes from the spring MVC controller method and it will be transformed into JSON automagically and be available to the client.  The key piece of magic here is the @ResponseBody tag which tells spring that the return value should make up the whole of the response body of the Http Response. Also the produces = .. value tells spring to use the Jackson processor because we can the application/json mime type as the output.

Here is an example


    @RequestMapping(value = "/gettopics", method = RequestMethod.GET, produces = "application/json")
    @ResponseBody
    public List<String> getTopics(final HttpServletRequest request)
    {
        final List<String> topics = new ArrayList<String>();
        topics.add("topic1");
        topics.add("topic2");

        return topics;
    }


Here the topics List object gets changed to a javascript list.  This can be processed on the client side by getting a result object

    for (var i=0; i<result.length; i++){
        alert(result[i]);
    }

And that is basically it.  Obviously your choice of javascript library to do the ajax request will have an impact here.  JQuery or Dojo would be the most common.

Accepting JSON

Accepting an json object into a Spring MVC method is a little more tricky.  Firstly you have to create an object to marshal into such as

    public class JsonExample {

        /** Value 1. */
        private final String value1;

        /** Value 2. */
        private final String value2;

        /**
         * Construct this object.  The benefit here is that this object is now immutable.
         */
        @JsonCreator
        public JsonExample(@JsonProperty("value1") final String value1,
                           @JsonProperty("value2") final String value2){
            this.value1 = value1;
            this.value2 = value2;
        }

        /**
         * Get the first value
         */
        public String getValue1(){
            return value1;
        }
    }

The annotations here tell Jackson how to marshal the JSON into this java object.  However, if you don't want an immutable object you just create getters and setters and you don't need any annotations at all! In the MVC controller method we simply have a @RequestBody rather than @ResponseBody this time and it all just works.


    @RequestMapping(value = "/settopics", method = RequestMethod.POST)
    @ResponseBody
    public void setTopics(final HttpServletRequest request, @RequestBody final JsonExample jsonExample)
    {
        ...
    }

Here the @ResponseBody seems like it should be surplus to requirements but the client doesn't like it if it isn't there.

In the web client a Javascript object is created

    var topics = {
        value1 : 'my topic',
        value2 : 'another topic'
    };

    var stringToSend = json.stringify(topics);

Again the choice of javascript library to make this call is down to the user but here the dojo/json module has been used.  The content headers need to be set on the post request


    Content-Type : 'application/json'

Posting a List of Objects

You would think that if you posted a list of object then you could just declare List<JsonExample> in the spring method but unfortunately this doesn't work.  Instead you have to declare an extension to the List object such as

    public class JsonExampleList extends ArrayList<JsonExample> {
        private static final long serialVersionUID = 3412220511906097746L;
    }

It doesn't require anything in it at all but helps Jackson sort out what you really mean and then the marshalling can continue.  Without doing this Jackson will convert to a LinkedHashMap of values and you can process this manually if you want to but the tip above will help Jackson sort it out.