
Project Overview
Objective
To build a serverless, progressive web application (PWA) with React using a test-driven development (TDD) technique. The application uses the Google Calendar API to fetch upcoming events.
Planning
User Stories and Test Scenarios
User Stories format
As a [role], I should be able to [action] So that [benefit]
- BDD Principle: written in Gherkin's "Given-When-Then"
- Given represents the context of the scenario. In what type of situation would this scenario arise?
- When represents the user interaction or behavior. What does the user need to do for this scenario to come into play? Ideally, you should narrow this down to one action per scenario.
- Then represents the expected outcomes of the scenario. What should happen when the user performs this specific action in this specific content?
FEATURE 1: FILTER EVENTS BY CITY
User Story
As a user I should be able to “filter events by city” So that I can see the list of events that take place in that city
Scenario 1: When user hasn’t searched for a city, show upcoming events from all cities.
- BDD Principle
- Given user hasn’t searched for any city
- When the user opens the app
- Then the user should see a list of all upcoming events
Scenario 2: User should see a list of suggestions when they search for a city.
- BDD Principle
- Given the main page is open
- When user starts typing in the city textbox
- Then the user should see a list of cities (suggestions) that match what they’ve typed
Scenario 3: User can select a city from the suggested list.
- BDD Principle
- Given he user was typing “Berlin” in the city textbox and the list of suggested cities is showing
- When the user selects a city (e.g., “Berlin, Germany”) from the list
- Then their city should be changed to that city (i.e., “Berlin, Germany”) And the user should receive a list of upcoming events in that city
FEATURE 2: SHOW/HIDE AN EVENT’S DETAILS
User Story
As a user I should be able to “collapse and expand an event by clicking ” So that I can see hide or see the details of an event
Scenario 1: An event element is collapsed by default.
- BDD Principle
- Given user is on the main page
- When nothing is selected
- Then then the event details will be 'collapsed' or hidden
Scenario 2: User can expand an event to see its details.
- BDD Principle
- Given user wants to see more details of a specific event
- When user clicks on the event to 'expand'
- Then the details for that event will be shown
Scenario 3: User can collapse an event to hide its details.
- BDD Principle
- Given an event has been 'expanded' and the details are shown and the user wants to 'collapse' or hide the details
- When the user wants to hide the details, the user needs to click on that event
- Then then the event details will be 'collapsed' or hidden
FEATURE 3: SPECIFY NUMBER OF EVENTS
User Story
As a user I should be able to “specify the number of events displayed” So that I can see the number of events I want to see.
Scenario 1: When user hasn’t specified a number, 32 is the default number of events.
- BDD Principle
- Given the user is shown a list of events
- When the user has not specified a number of events to be shown
- Then the default of 32 events will be displayed
Scenario 2: User can change the number of events they want to see.
- BDD Principle
- Given User can change the number of events they want to see.
- When the user specifies a number as to how many events they want to see
- Then the user specified number will be the amount of events that will be displayed to the user
FEATURE 4: USE THE APP WHEN OFFLINE
User Story
As a user I should be able to “use the app offline” So that I can have access to the cached data and can still see my events.
Scenario 1: Show cached data when there’s no internet connection.
- BDD Principle
- Given the user has no internet connection
- When they access the app
- Then they can still access and view data from the cache
Scenario 2: Show error when user changes the settings (city).
- BDD Principle
- Given the user locates to another location
- When the user changes their settings
- Then an error message will be shown to the user
FEATURE 5: DATA VISUALIZATION
User Story
As a user I should be able to “see charts with the number of upcoming events in each city” So that I can have a better overview of the events in each city
Scenario 1: Show a chart with the number of upcoming events in each city.
- BDD Principle
- Given user is on the app
- When the user wants to have a better overview of the number of events in each city
- Then the app will display charts with the information
Testing
Unit Testing
Testing each individual "unit" (function) of an app to ensure that they work correctly by themself.
- Jest is a test runner that was implemented to perform the unit tests.
- Enzyme is a shallow rendering API. This allows the program to be rendered only "one level deep" and not rendering a components children or a DOM. This allows Jest to perform unit testing as only the components are rendered.
Integration Testing
Testing that each individual "unit" (function) of an app works well with the the other parts (cross-component functionality).
- Jest is a test runner that was implemented to perform the integration tests.
- Enzyme mount() is a full rendering API. This allows components to be fully rendered.
- Mock data was used to test the components and the functionality between them or its children
Acceptance Testing
Testing the application's features, written following the behavior-driven development (BDD) style.
- Jest-Cucumber uses Jest as a test runer with a Cucumber-based library that is added to the Jest.
- Cucumber tests are written in Gherkin's "Given, When, Then" syntax.
End-to-End Testing
Testing the whole application and ensuring that it works as it is supposed to.
- Puppeteer used to test apps on the Chrome Chromium browser. Simulates user actions to ensure that the UI interactions work correctly as intented.
Development
Technologies Used
- HTML
- CSS / React Bootstrap
- React:
- set up using create-react-app command
- Serverless functions:
- Uses a serverless architecture where each function is deployed individually in the cloud.
- The infrastructure behind the function will be handled by the cloud provider.
- AWS Lambda was used to provide an authorization server using serverless functions as only access tokens are needed.
- It creates a valid OAuth2 token which is needed to access the Google Calendar API
- Google Calendar API
- A protected API that requires authentificaion, this will then retrieve data about upcoming events.
- When a user visits the site it checks if the user has been authorized or not. If they haven't they will be redirected to the Google authorization screen asking them to sign in.
- After successful login the user will be redirected to the app with a code parameter in the URI
- This code is then sent to the serverless API (AWS Lambda) where its validity is checked with google and if successful it returns an access code.
- This token is then saved in a cookie which then is used to get the events from the Google Calendar API.
Authentication Process
Challenges:
-
I wanted more practice in localStorage therefore I decided to implement a toggle for dark and light mode at the top of the page.
-
The most difficult part was having this saved from the start screen to the data screen as the user logs in with google thereby refreshing the page. So I had to make sure that the user preference would be saved for the next visit / reload of the page.