This is an internal documentation. There is a good chance you’re looking for something else. See Disclaimer.

Development

Setup

Warning

The environment variable FONTAWESOME_NPM_AUTH_TOKEN has to be available otherwise the setup command will fail. With osx this can be done with:

launchctl setenv FONTAWESOME_NPM_AUTH_TOKEN {TOKEN}

or with linux:

FONTAWESOME_NPM_AUTH_TOKEN={TOKEN}

Make sure to check if the variable is available. Maybe a restart is required. The value of {TOKEN} can be found in the ansible vault

This variable is used in the .npmrc file.

Warning

Node version per release

  • <= 3.5: Node v16

  • >= 3.6: Node v20

You can use Node v20 for <= 3.5 if you pass --openssl-legacy-provider as argument (e.g. yarn start --package=admin --openssl-legacy-provider.)

Install VS Code on your machine. Useful plugins which you can install:

Install Yarn and execute the following commands:

git clone git@gitlab.com:toccoag/tocco-client.git
cd tocco-client
yarn setup

For some packages/components you may need secret keys or passwords you can’t commit or save in the codebase.

Enter this command to create your /.env file containing the known secrets without values.

yarn plop Env

Code Styleguide

See Coding Styleguide

Start a package

yarn start --package={package-name} --backend={backend-url}

yarn start-widget --key={widget-config-key} --backend={backend-url}

Open http://localhost:3000 and wait for a finished build.

Note

start-widget command will retrieve the widget config and start the widget package automatically. Otherwise the widget can be started with yarn start --package={widget-package-name} as well. But then de ./dev/input.json has to be filled in with dummy config data.

Note

Hot reloading will allow parts of the application to be live reloaded when the source code changes. Keep in mind that hot reloading will not work for sagas.

Optional parameters

--backend={BACKEND_URL}

Enable an alternative backend. E.g. master deployment of Tocco. (default: http://localhost:8080)

This command will locally start the admin and uses the master deployment as backend.

yarn start --package=admin --backend=https://master.tocco.ch

Make sure that the selected backend has both application properties nice2.web.cookie.sameSite=None and nice2.web.allowedRequestOrigins=http://localhost:3000 set. Otherwise you will get CORS errors when trying to connect to it. By default, these properties are only set for our test customer installations.

Deploy package to local backend

For testing purposes it’s useful to test a package (admin, action or widget) in production mode. Therefore it’s easiest to deploy the package to the locally cloned nice2.

yarn nice2:deploy-package --package={package-name}

This script gets the nice2 repository folder with the same tocco version and copies the generated production build inside the repo folder.

Warning

This script needs the environment variable NICE2_REPO_BASE_PATH. The NICE2_REPO_BASE_PATH can be added to the .env file inside the tocco-client root folder and has to be set to the parent folder of all nice2 repositories.

Note

The deploy package script for bundles can be extended with --app argument to define which apps should be bundled. The build time can be significantly decreased and it’s useful for testing purposes when only working on one or a few apps.

Example:

yarn nice2:deploy-package --package=widget-bundle --app=entity-browser --app=docs-browser

Storybook

It might be helpful to start up Storybook locally to test the current state of development. Most of the components or packages have a dedicated story to run them isolated. Storybook can be started with the following command:

# run against local nice2
yarn storybook

# run against https://master.tocco.ch
yarn storybook:master

Use BACKEND={BACKEND_URL} yarn storybook to enable an alternative backend.

Add new story file

  • suffix filename with *.stories.js

  • add package in stories list in storybook/main.js

Unit Tests

Tests are using following tools and libraries:

Run unit tests with Jest via lerna

yarn test

Run all unit tests directly (not via lerna)

yarn test:jest

Optional parameters

--watch

Run jests watch mode

Note

If working with IntelliJ single tests or test-suites can be run in the IDE directly. Just set the jest.config.js file in the Jest run configuration.

Chai Assertions

We use BDD (Behaviour Driven Development) assertions with the base of expect.

See: Chai Assertions for the API

React Testing Library

The React Testing Library (RTL) only provides a full render function. In addition the RTL operates on the outputted html and React components cannot be used for any assertion or prop updates.

Render without redux

import {screen} from '@testing-library/react'
import {testingLibrary} from 'tocco-test-util'

it(() => {
  testingLibrary.renderWithIntl(<MyComp />)
  expect(screen.getAllByText('client.comp.textid')).to.exist
})

Render with redux

import {testingLibrary} from 'tocco-test-util'

import reducers, {sagas} from '../../modules/reducers' // import reducers and sagas from package

it(() => {
  const input = {}
  const store = appFactory.createStore(reducers, sagas, input)
  store.dispatch(...) // dispatch actions to prefill state
  testingLibrary.renderWithStore(<MyComp />, {store})
})

Prevent render with mocking

When a child component should not render itself it can be mocked. This can be useful if only the existens of a component is important but not its behaviour itself.

import {screen} from '@testing-library/react'
import {testingLibrary} from 'tocco-test-util'

jest.mock('tocco-entity-list/src/main', () => () => <div data-testid="entity-list" />)

it(() => {
  testingLibrary.renderWithIntl(<MyComp />)
  expect(screen.getByTestId('entity-list')).to.exist
})

End-to-End Tests

End-to-End (e2e) tests are written and run with Cypress.

Local Cypress Setup

Postgres User

To ensure that Cypress scripts are able to log into the postgres server without using a password prompt one of the three settings has to be set up:

  1. set trust authentication method

  2. create ~/.pgpass for postgres database and postgres user

  3. set POSTGRES_PASSWORD in .env (see Environment variables)

Authentication Trust Method

  • set trust method in pg_hba.conf for local

  • restart postgresql

.pgpass file

  • create ~/.pgpass file (see: pgpass file)

  • add entry for postgres user on postgres database

    # hostname:port:database:username:password
    localhost:5432:postgres:postgres:postgres
    
  • set correct file permission

    chmod 0600 ~/.pgpass
    

Environment variables

A .env file in the root folder is needed so that test can authenticate to the nice2 backend.

Variable

Description

CYPRESS_USER

Tocco user name

CYPRESS_PASSWORD

Password for Tocco user

CYPRESS_USER_PASSWORD_HASH

The hash for the CYPRESS_PASSWORD

CYPRESS_API_KEY

Tocco API Key (needed for test-data setup via REST)

CYPRESS_USER_API_KEY_HASH

The hash for the CYPRESS_API_KEY

Note

The values for the Cypress environment variables can be found in the ansible vault.

Furthermore there are optional environment variables which can be set to overwrite some default values.

Variable

Description

Default value

POSTGRES_USER

postgres superuser (for test db restore and setup)

none (login user is taken)

POSTGRES_PASSWORD

pwd for postgres superuser [1]

none

HIBERNATE_MAIN_SERVERNAME

postgres hostname

localhost

HIBERNATE_MAIN_USER

postgres user for test database [2]

nice

HIBERNATE_MAIN_PASSWORD

postgres user password for test database

nice

HIBERNATE_MAIN_DATABASENAME

postgres test database name [3]

test_cypress

HIBERNATE_MAIN_SSLMODE

nice2 ssl mode

disable

BACKEND_URL

nice2 hostname

http://localhost:8080

CYPRESS_BASE_URL

nice2 hostname (officical Cypress env)

http://localhost:8080

Explanation

Run Cypress

Warning

Before you start ensure that you’ve properly set up Cypress locally (Local Cypress Setup).

# start nice2 via gradle and widget-server on localhost:3000
yarn cypress:nice2

# or run both separately
yarn nice2:run
yarn widgets:serve

# deploy local package to nice2 for testing purposes (OPTIONAL)
yarn  nice2:deploy-package --package=admin

# run cypress
yarn cypress:run
# or open cypress dashboard
yarn cypress:open

Note

Per default a database with name test_cypress is created right before running nice2. To overwrite the database name set HIBERNATE_MAIN_DATABASENAME environment variable (see Environment variables).

Cypress on CI

On CI (gitlab) the nice2 and postgres instances are running in Docker: Nice2 Registry, Postgres Registry.

A test run saves the generated video artefacts for one week. Those artefacts can be found on the executed pipeline for further failure investigation.

Writing Cypress Tests

Folder structure

In the figures below, you can see our folder structure for the Cypress tests. All tests are integrated into this structure. When the videos are created, they are also created with the same folder structure.

../../_images/cypress_folder_structure.jpg

You will find the e2e folder in your Cypress directory on the client.

Do’s and Dont’s

See also Cypress Best Practices

data-cy attribute

Use data-cy attribute to select a elements. Using keys or unique identifiers helps to get the correct element out of many (e.g. data-cy="list-row-1229"). Do not use CSS classes for element selection except for external libraries.

Data-cy naming

<prefix> - names

Prefix

Description

Examples

btn

Button

btn-confirmation

infobox

Infobox

infobox-newregistrations

export-item

For different export items in the export action

export-item-phonelist

communication

For different communication items in the communication action

communication-sms

action

For the different action groups like new, delete, output, etc.

action-delete

action-item

For the different actions

action-item-createTodo

list-row

Row in the table. Use the Entity-Id as the name

list-row-1

header-cell and list-cell

Are used in the tables. The name should be the relation or field name.

header-cell-firstname

form-field

Input fields in the admin. The name should be the relation or the field name.

form-field-firstname

box

For the boxes in the detail-form

box-masterdata

admin-menuitem

For the items in the admin menu

admin-menuitem-address

Create Cypress Tasks for seeding

Only seed data via Cypress Tasks and do not run REST APIs inside a test directly. Use the returned data for better testing:

cy.task('db:seed:entity-browser').then(response => {
  const {pk} = response
  visitEntityBrowser(pk)
})

cy.task('db:seed:user').then(user => {
  const {firstname} = user
  ...
  cy.getByAttr('input-detailForm-firstname').type(user.firstname)
  ...
})

Test data

Test data can be added via REST API inside a Cypress Tasks.

  • Each test data task should be prefixed with db:seed:.

  • A test data task can be named and created for generic purposes or for single tests/specs only.

  • If possible the task should return the created IDs and as much data as possible.

Helpers

Empty Database

Every test should be independent and not rely on any data inside the database. Before each test the database should be emptied to start on a fresh db.

cy.task('db:empty')

Login

A test should not log in via UI. Use login helper instead.

cy.login()

// for widgets running on widget-server
cy.login({backendUrl: 'http://localhost:3000'})

Get Element by data-cy Attribute

To select HTML element data-cy attributes should be used. CSS classes are not allowed except for external libraries. The getByAttr helper creates a query selector for the data-cy attribute.

cy.getByAttr('admin-nav')

Process

Run Nice2

  1. Restore DB from existing DB dump (create empty DB when no dump is available)

  2. Run DB refactoring

  3. Run Nice2

  4. Initialize DB

    1. Crate Tocco User and API Key for Cypress (See Environment variables)

    2. Create DB dump

Test Run

  1. Empty DB

    1. Forcefully restore DB from existing DB dump (created on nice2 start up)

  2. Seed DB via REST API

  3. Login

  4. Run Test

Code Generators

The project provides some code generators. Generators are developed with Plop and can be executed with:

yarn plop

There are the following generators:

  • Package

    • used for new packages, creates all file structure for a package

  • Env

    • used initially for set up the environment, initiate a .env file with your environment variables

  • Bundle app

    • used for adding a package to a bundle (e.g. a widget to the widget-bundle)

Build bundle

Sometimes it’s desired to only build a package for testing purposes.

yarn compile:dev --package={package-name}
yarn compile:prod --package={package-name}

Parameters

--bundle-analyzer

Opens BundleAnalyzerPlugin to investigate the bundle sizes.

--backend={BACKEND_URL}

To enable an alternative backend.

NPM authentication

We use the default NPM Registry to upload the packages. All developers use the same user on npm (user “tocconpm” with email admin@tocco.ch). To setup the authentication execute following command:

npm adduser

The password can be found on in the ansible vault.