Commenting Standards - bcgov/PIMS GitHub Wiki

Frontend (React Typescript / TSX)

Introduction

The PIMS frontend React application uses the TSDoc commenting standard.

For any questions, for insight into how TSDoc is structured, please refer to the TSDoc documentation.

Components

Required Fields

  • @description - A brief description of why the component exists and what it does
  • @author - The author(s) of the component, in the format of [Author 1, Author 2, ...]
  • @param? - One @param tag for the prop interface for the given component, and one @param tag for each prop. Can be omitted if it takes no props
  • @example - An example of what a call of this component might look like

Example:

./frontend/Counter.tsx
/**
 * @description This component renders a number and two buttons which can increment/decrement said number.
 * 
 * @author [Miles Morales, Steve Rogers]
 * @param {ICounterProps} props - The props for the component
 * @param {number} props.initialValue - The initial value for the counter to start at 
 *
 * @example 
 * <Counter initialValue={10} />
*/

// const Counter = ...

Hooks

Required Fields

  • @description - A brief description of why the hook exists and what it does
  • @author - The author(s) of the hook, in the format of [Author 1, Author 2, ...]
  • @param? - One @param tag for each argument the hook takes in
  • @returns - The return value of the hook
  • @example - An example of what a call of this hook might look like

Example:

./frontend/useWidth.ts
/**
 * @description This hook tracks the current width of the given element
 *
 * @author [Bruce Banner, Scott Lang]
 * @param {HTMLElement} element - The element whose width should be tracked
 * @returns {number} The current element width in pixels
 * 
 * @example
 * const helloElement = <p>hello!</p>
 * const width = useWidth(helloElement) // width === 125
 */

// const useWidth = ...

Redux Slices

Required Fields

  • State Interface

  • Slice

    • @description - A brief description of why the slice exists and what it does
    • @author - The author(s) of the slice, in the format of [Author 1, Author 2, ...]
    • @extends - The base class or interface the slice extends from
  • Reducers

    • @description - A brief description of why the reducer exists and what it does
    • @author - The author(s) of the reducer, in the format of [Author 1, Author 2, ...]
    • @param - One @param tag for each argument the reducer takes in
    • @returns - The return value of the reducer

Example:

./frontend/UserSlice.ts
/**
 * @description The state of the user slice.
 * 
 * @interface
 */
export interface UserState {

  /**
   * @property
   * @description The user's name.
   */
  name: string;

  /**
   * @property
   * @description The user's age.
   */
  age: number;
}

/**
 * The initial state of the user slice.
 */
const initialState: UserState = {
  name: '',
  age: 0,
};

/**
 * @description This slice stores user info
 *
 * @author [Rick Rubin, Johnny Cash]
 * @extends {ActionReducerMap<UserState>}
 */
export const userSlice = createSlice({
  name: 'user',
  initialState,
  reducers: {
    /**
     * @description Sets the user's name.
     *
     * @param {UserState} state - The current state of the slice.
     * @param {PayloadAction<string>} action - The action object.
     *
     * @returns {void}
     */
    setName(state, action: PayloadAction<string>) {
      state.name = action.payload;
    },
    /**
     * @description Sets the user's age.
     *
     * @param {UserState} state - The current state of the slice.
     * @param {PayloadAction<number>} action - The action object.
     *
     * @returns {void}
     */
    setAge(state, action: PayloadAction<number>) {
      state.age = action.payload;
    },
  },
});

export const { setName, setAge } = userSlice.actions;

Interfaces

Required Fields

  • Interface
    • @description - A brief description of why the interface exists and what it does
    • @author - The author(s) of the interface, in the format of [Author 1, Author 2, ...]
    • @interface - Denotes that what is being commented is an interface
  • Interface Property
    • @description - A brief description of why the property exists and what it is used for

Example:

./frontend/IVehicle.ts
/**
 * @description An interface that represents a vehicle.
 *
 * @author [Zach Bourque]
 * @interface
 */
export interface IVehicle {

  /**
   * @description The make of the vehicle, such as "Ford" or "Toyota".
   */
  make: string;

  /**
   * @description The model of the vehicle, such as "Mustang" or "Camry".
   */
  model: string;

...

Utility Functions

Required Fields

  • @description - A brief description of why the function exists and what it does
  • @author - The author(s) of the function, in the format of [Author 1, Author 2, ...]
  • @param? - One @param tag for each argument the function takes in
  • @returns - The return value of the function
  • @example - An example of what a call of this function might look like

Examples:

./frontend/IVehicle.ts
/**
 * @description Formats the GUID given by Keycloak Gold to the standard GUID format.
 *
 * @author [Stevie Wonder]
 * @param {string} input - The GUID given by Keycloak Gold
 * @returns {string} - The same GUID in standard GUID format
 *
 * @example
 * const guid: string = convertToGuidFormat("517189e00b5a4fb184ab803b7d19271a"); // guid === t"517189e0-0b5a-4fb1-84ab-803b7d19271a"
 */

Cypress

Writing Cypress E2E Tests

Familiarize yourself with Cypress Best Practices.

+ Here, we will go over the essentials and give examples.

Template:

This template creates a test suite named Summary of entire test suite in Templates/template.cy.ts. It has 1 test named Visit home page. Before each test is run, the beforeEach() code is executed. This function is authenticating with Keycloak SSO and running any clean up code.

./frontend/cypress/e2e/Templates/template.cy.ts
/**
 * @author Template Maker <[email protected]>
 * @description Tests creating a template.
 * @components TemplateContainer
 * @page Templates
 * @route /templates
 * @tests Visit home page.
 */

describe('Summary of entire test suite', () => {
  beforeEach(function() {
    // Keycloak SSO authentication.
    cy.kcLogout();
    cy.kcLogin(Cypress.env('default_keycloak_user'));

    /* ---------------------------------------------------------------------
                          CLEAN UP: Run before tests.
    * --------------------------------------------------------------------- */

    cy.visit(`/`);
  });

  /* ---------------------------------------------------------------------
                        TEST CASE: Visit home page.
  * --------------------------------------------------------------------- */

  /**
   * @title Visit home page
   * @description Tests visiting the applications home page.
   */

  it('Visit home page', () => {
    cy.visit('/');
  });
});

Commenting Tests

Good commenting makes it easier for everyone to understand your code. It will help you when you're looking over your own code, showing someone your code, or someone else looking at your code when you're not around.

At the top of the test file:

+ Comment the top of your test file with the following to give a good summary of what the test suite is doing.
/**
 * @author John Doe <[email protected]>
 * @description Tests search filter and map controls.
 * @components Map, PropertyFilter, InfoContent, MapSdeBarLayout, BasemapToggle, LegendControl
 * @page Home
 * @route /mapview
 * @tests Search and filter bar functionality, Map Controls.
 */

Above every test case:

+ Comment a test case with the following header.
/* ---------------------------------------------------------------------
                        TEST CASE: Map controls.
* --------------------------------------------------------------------- */

/**
 * @title Map controls
 * @description Tests controls and buttons on the map.
 */

it('Map controls', () => {
});

Within each test case:

+ Add comment headers to separate sections within test cases  
+ as well as single line comments to explain what a function is doing.
/* <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
              Search
* <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */

// Search.
cy.intercept('/api/properties/search/wfs*').as('searching');
cy.get('[data-testid="search-btn"]')
  .should('be.visible')
  .click();

// Wait for search to load.
cy.wait('@searching').wait(3000);

Backend (ASP.NET / C#)

General

Controllers

Data Access Layer (DAL)

Services

⚠️ **GitHub.com Fallback** ⚠️