Acceptance Testing of a Feature in Open Event Frontend

In Open Event Frontend, we have integration tests for ember components which are used throughout the project. But even after those tests, user interaction could pose some errors. We perform acceptance tests to alleviate such scenarios.

Acceptance tests interact with application as the user does and ensures proper functionality of a feature or to determine whether or not the software system has met the requirement specifications. They are quite helpful for ensuring that our core features work properly.

Let us write an acceptance test for register feature in Open Event Frontend.

import { test } from 'qunit';
import moduleForAcceptance from 'open-event-frontend/tests/helpers/module-for-acceptance';

moduleForAcceptance('Acceptance | register');

In the first line we import test from ‘ember-qunit’ (default unit testing helper suite for Ember) which contains all the required test functions. For example, here we are using test function to check the rendering of our component. We can use test function multiple times to check multiple components.

Next, we import moduleForAcceptance from ‘open-event-frontend/tests/helpers/module-for-acceptance’ which deals with application setup and teardown.

test('visiting /register', function(assert) {
  visit('/register');

  andThen(function() {
    assert.equal(currentURL(), '/register');
  });
});

Inside our test function, we simulate visiting  /register route and then check for the current route to be /register.

test('visiting /register and registering with existing user', function(assert) {
  visit('/register');
  andThen(function() {
    assert.equal(currentURL(), '/register');
    fillIn('input[name=email]', [email protected]');
    fillIn('input[name=password]', 'opev_test_user');
    fillIn('input[name=password_repeat]', 'opev_test_user');
    click('button[type=submit]');
    andThen(function() {
      assert.equal(currentURL(), '/register');
      // const errorMessageDiv = findWithAssert('.ui.negative.message');
      // assert.equal(errorMessageDiv[0].textContent.trim(), 'An unexpected error occurred.');
    });
  });
});

Then we simulate visiting /register route and register a dummy user. For this, we first go to /register route and then check for the current route to be register route. We fill the register form with appropriate data and hit submit.

test('visiting /register after login', function(assert) {
  login(assert);
  andThen(function() {
    visit('/register');
    andThen(function() {
      assert.equal(currentURL(), '/');
    });
  });
});

The third test is to simulate visiting /register route with user logged in and this is very simple. We just visit /register route and then check if we are are at / route or not because a user redirects to / route when he tries to visit /register after login.

And since we checked for all the possible combinations, to run the test we simply use the following command-

ember test --server

But there is a little demerit to acceptance tests. They boot up the whole EmberJS application and start us at the application.index route. We then have to navigate to the page that contains the feature being tested. Writing acceptance tests for each and every feature would be a big waste of time and CPU cycles. For this reason, only core features are tested for acceptance.

Resources

Maintain Aspect Ratio Mixin on Open Event Frontend

The welcome page of the Open-Event-Frontend is designed to contain cards that represent an event. A user is directed to the event-details page by clicking on the corresponding card. The page consists of an image that serves as the banner for the event and an overlapping div to provide some contrast against the image. A comment may also be added onto the image and along with the overlapping div it is wrapped in a container div.

Since we have given a specific height to the contrasting div, the background image shrinks according to the screen size but the contrasting div does not whenever we go from a large screen to a smaller screen.

Mobile view (before):-

We want our contrasting div also to resize in accordance to the image. To do it, we first define a sass mixin to maintain a common aspect ratio for image and overlapping div. Let us see it’s code.

 @mixin aspect-ratio($width, $height) {
    position: relative;
    &:before {
      display: block;
      content: "";
      width: 100%;
      padding-top: ($height / $width) * 100%;
    }
    > .content {
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
    }
    > img {
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
    }
  }

So what does this mixin actually doing is we are passing the height and width of the image and we are defining a pseudo element for our image and give it a margin top of (height/width)*100 since this value is related to image width (height: 0; padding-bottom: 100%; would also work, but then we have to adjust the padding-bottom value every time we change the width). Now we just position the content element and image as absolute with all four orientations set to 0. This just covers the parent element completely, no matter which size it has.

Now we can simply use our mixin by adding the following line of code in out container div

@include aspect-ratio(2, 1);

Here we want to maintain a 2:1 aspect ratio and the user is also expected to upload the image in the same aspect ratio. Therefore, we pass width as 2 and height as 1 to our mixin.

Now when we resize our screen both the image and the overlapping div resize maintaining 2:1 aspect ratio.

Mobile view (after):-

Resources

  • mademyday blog describes a method of using pseudo elements to maintain an element’s aspect ratio.
  • css-tricks snippet.

Image Cropper On Ember JS Open Event Frontend

In Open Event Front-end, we have a profile page for every user who is signed in where they can edit their personal details and profile picture. To provide better control over profile editing to the user, we need an image cropper which allows the user to crop the image before uploading it as their profile picture. For this purpose, we are using a plugin called Croppie. Let us see how we configure Croppie in the Ember JS front-end to serve our purpose.

All the configuration related to Croppie lies in a model called cropp-model.js.

 onVisible() {
    this.$('.content').css('height', '300px');
    this.$('img').croppie({
      customClass : 'croppie',
      viewport    : {
        width  : 400,
        height : 200,
        type   : 'square'
      },
      boundary: {
        width  : 600,
        height : 300
      }
    });
  },

  onHide() {
    this.$('img').croppie('destroy');
    const $img = this.$('img');
    if ($img.parent().is('div.croppie')) {
      $img.unwrap();
    }
  },

  actions: {
    resetImage() {
      this.onHide();
      this.onVisible();
    },
    cropImage() {
      this.$('img').croppie('result', 'base64', 'original', 'jpeg').then(result => {
        if (this.get('onImageCrop')) {
          this.onImageCrop(result);
        }
      });
    }

There are two functions: onVisible() and onHide(), which are called every time when we hit reset button in our image cropper model.

  • When a user pushes reset button, the onHide() function fires first which basically destroys a croppie instance and removes it from the DOM.
  • onVisible(), which fires next, sets the height of the content div. This content div contains our viewport and zoom control. We also add a customClass of croppie to the container in case we are required to add some custom styling. Next, we set the dimensions and the type of viewport which should be equal to the dimensions of the cropped image. We define type of cropper as ‘square’ (available choices are ‘square’ and ‘circle’). We set the dimensions of our boundary. The interesting thing to notice here is that we are setting only the height of the boundary because if we pass only the height of the boundary, the width will be will be calculated using the viewport aspect ratio. So it will fit in all the screen sizes without overflowing.

The above two functions are invoked when we hit the reset button. When the user is satisfied with the image and hits ‘looks good’ button, cropImage() function is called where we are get the resulting image by passing some custom options provided by croppie like base64 bit encoding and size of cropped image which we are set to ‘original’ here and the extension of image which is we set here as ‘.jpeg’. This function returns the image of desired format which we use to set profile image.

Resources

Declaring Ember Data Model Defaults in Open Event Frontend

This article will illustrate the ways to declare the model defaults for JavaScript data types ‘boolean’, ‘string’, ‘number’, ‘object’ and ‘array’ as used in Open Event frontend project.

While working with ember-data models which define the properties and behaviour of data, in Open Event frontend project, we needed to preset the values for certain attributes if they are not supplied along with data. To preset the values in ember-data we need to specify the default values to the attribute. The process of setting the default values is very much similar to the way we handle it in other databases like MySQL and we might have certainly done it many times there. In ember, we set the values like this.

export default Model.extend({
 type : attr('string', { defaultValue: 'text' }),
 isRequired : attr('boolean', { defaultValue: false })
});


This way we could set values for attributes having data types, ‘boolean’, ‘string’ and ‘number’. But when it came to data types, ‘object’ and ‘array’ we were unable to set the default values in similar way reason being ember data does not provide support for ‘array’ and ‘object’ data types. Also, we tried to play around by not providing the first argument to the DS.attr() method, then Ember does not remain the value for that particular attribute empty or unhandled rather it forced to matching JavaScript type. The other and the obvious way which clicked to us was this.The attributes are properties defined to convert the JSON data coming from our server into a record, and serializing a record to save back to the server after it has been modified. In above code we defined that ‘type’  has a default value of ‘text’ and ‘isRequired’ has default value ‘false’ which will be present at the time of model’s creation.

export default Model.extend({
 startTime : attr('object', { defaultValue: {} })
});


But soon after executing the code, we got a warning which can be seen below.The above code implies that whenever we create a new
event model then it would be expected to have an attribute startTime with value {}.

Non primitive defaultValues are deprecated because they are shared between all instances. If you would like to use a complex object as a default value please provide a function that returns the complex object.

The warning explains that ember-data model extends from Ember.Object, which means that arrays and objects will be shared among all instances of that model hence the use of non-primitive (apart from boolean, number & string) default values are deprecated.

Now again we thought of something that can handle ‘array’ and ‘object’ data types. We thought of adding a function which would convert them to the custom type. To add that we needed to provide proper serialize and deserialize methods for processing the data properly which was a bit tedious process and increase the overall complexity of code both in terms of execution as well as understanding.

After reading the available resources, we got to know that the defaultValue accepts the function as well. So what we finally did was passed a function which will add the months and days to the date object based on the current time which can be calculated using moment.

export default Model.extend({
 startTime : attr('date', { defaultValue: () => moment().add(1, 'months').startOf('day').toDate() }) 
});


The ability to pass afunction to defaultValue proved very helpful. It suits best if we want to set custom defaults.That’s it! Passing the function will ensure that every
startTime attribute contains it’s own date instance.

Additional Resources:

**image is licenced under free to use CC0 Public Domain

Step by step guide for Beginners in Web Development for Open Event Frontend

Originally the frontend and backend of the Open Event Server project were handled by FLASK with jinja2 being used for rendering templates. As the size of the project grew, it became difficult to keep track of all the modifications made on the frontend side. It also increased the complexity of the code. As a result of this, a new project Open Event Frontend was developed by decoupling the backend and frontend of the Open Event Orga Server. Now the server is being converted fully into functional API and database and the open event frontend project is primarily the frontend for the Open event server API where organisers, speakers and attendees can sign-up and perform various functions.     

The Open Event Frontend project is built on JavaScript web application framework, “Ember.js”. To communicate with the server API Ember.js user Ember data which is a data persistence module via the exposed endpoints. Suppose if you’re coming from the Android background, soon after diving into the web development you can relate that the web ecosystem is much larger than the mobile one and for the first timers it can be difficult to adopt with it because of the reason that in web there are multiple ways to perform a task which can be restricted to very few in the case of Android. For web applications, one can find that much more components are involved in setting up the project while in android one can easily start contributing to project soon after compiling it in Android Studio. One thing which is relatable for both the android and web development is that in the case of android one has to deal with the varying screen sizes and compatibility issue while in the web one has to deal with adding support for different browsers and versions which can be really annoying.

Now let’s see how one can start contributing to the Open event frontend project while having no or a little knowledge of web development. In case if you’ve previous knowledge of JavaScript then you can skip the step 1 and move directly to another step which is learning the framework.

(Here all the steps have been explained in reference if you’re switching from Android  to Web development.)

Step 1. Learning the Language – JavaScript

Now that when you’ve already put your feet into the web development it’s high time to get acquainted with the JavaScript. Essentially in the case of Ember which is easy to comprehend, you can though start with learning the framework itself but the executables file are written in JavaScript so to write them you must have basic knowledge of the concepts in the language. Understanding of JavaScript will help in letting know where the language ends and where the framework starts. It will also help in better understanding of the framework. In my opinion, the basic knowledge of JavaScript like the scope of variables, functions, looping, conditional statements, modifying array and dictionaries, ‘this’ keyword etc. helps in writing and understanding the .js files easily. Also, sometimes in JavaScript, an error might not be thrown as an exception while compiling but it may evaluate the program to undefined, knowledge of the language will help in debugging the code.

Step 2. Learning the Framework – Ember

Ember is a JavaScript Framework which works on Model-View-Controller(MVC) approach. The Ember is a battery included framework which generates all the boilerplate code including components, routes. Templates etc.  required for building an application’s frontend. It is very easy to understand and comprehend. In Ember, we can easily define the data models and relationships and ember will automatically guess the correct API endpoints. Apart from this, the documentation of the ember on its website is very much sufficient to start with. One can easily start developing applications after going through the tutorial mentioned on the ember’s website.  

Step 3. Testing

In the case of Android application development to write test we use android libraries like Mockito and Robolectric. Also, testing is a bit more difficult in Android app development because we have to explicitly write the test but it is a lot easier in the case of web development. In the case of Ember, it provides an ease of testing which no other framework and libraries provide. While generating a component or template ember itself generates the test files for them and all we have to do is to change them according to our requirement. Ember generates unit, acceptance and integration tests by making testing easier. So we don’t have to write the test explicitly we only have to modify the test files generated by ember.    

Step 4. Styling

In Android we have colors.xml, styles.xml, drawables, gradients, shapes etc. for styling our application but in the case of Web, we have Cascading Style Sheets (CSS) for styling our application. Simply using pure CSS make design complicated and difficult to understand, so to make it easier we combine a bunch of design elements with a style file and use Syntactically Awesome Style Sheets (Saas) with mixins to do that which makes creating styles a lot easier and more straightforward. So for styling, our web application one should have the knowledge of HTML as well as CSS.

In conclusion, I can say that learning web development requires learning a few things in parallel which includes learning a language, learning a framework, how to perform testing and different styling skills to make an application beautiful. Due to dynamic nature of the JavaScript and the sheer number of packages and components involved, as opposed to the safe environment that Android Studio provides, it can be sometimes really frustrating.  However, once learned the basics, the knowledge and skills can be easily transferred and applied over and over again.