This is an internal documentation. There is a good chance you’re looking for something else. See Disclaimer.
Development¶
Setup¶
Install Node
Warning
Node version per release
Node Version
Nice Versions
v16
3.1 - 3.5
v20
3.6 - 3.10
v22
3.11 -
You can use Node v20/v22 for <= 3.5 if you pass
--openssl-legacy-provider
as argument (e.g.yarn start --package=admin --openssl-legacy-provider
.)Install and enable Node Corepack.
Warning
Yarn is installed via package manager
Corepack
from Node. Therefore do not install Yarn with a os package manager.Setup environment variables
These environment variables are used in the
.yarnrc.yml
file:Key
Value
Usage
FONTAWESOME_NPM_AUTH_TOKEN
ansible vault
Mandatory - used for installing packages
NPMJS_AUTH_TOKEN
Optional - used for publishing packages to npm
With osx the variables can be added with:
launchctl setenv FONTAWESOME_NPM_AUTH_TOKEN {TOKEN} launchctl setenv NPMJS_AUTH_TOKEN {TOKEN}
or with linux:
FONTAWESOME_NPM_AUTH_TOKEN={TOKEN} NPMJS_AUTH_TOKEN={TOKEN}
Make sure to check if the variable is available. Maybe a restart is required.
Clone
tocco-client
:git clone git@gitlab.com:toccoag/tocco-client.git cd tocco-client yarn install
Setup
.env
file:yarn plop Env
Install VS Code on your machine. Useful plugins which you can install:
Prettier (more details)
ESLint (more details)
Jest
Code Styleguide¶
Start a package¶
Note
Whenever you change branches you need to run yarn install
.
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
|
Enable an alternative backend. E.g. master deployment of Tocco. (default: |
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 instorybook/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
|
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¶
Setup Nice2 (See Nice2 Setup)
Setup local postgres database (See Postgres Setup and Postgres User)
Setup
.env
file (See Setup and Environment variables)
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:
set trust authentication method
create
~/.pgpass
for postgres database and postgres userset
POSTGRES_PASSWORD
in.env
(see Environment variables)
Authentication Trust Method
set
trust
method inpg_hba.conf
for localrestart
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_API_KEY |
Tocco API Key (needed for test-data setup via REST) |
CYPRESS_USER_API_KEY_HASH |
The hash for the |
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 |
|
HIBERNATE_MAIN_USER |
postgres user for test database [2] |
|
HIBERNATE_MAIN_PASSWORD |
postgres user password for test database |
|
HIBERNATE_MAIN_DATABASENAME |
postgres test database name [3] |
|
HIBERNATE_MAIN_SSLMODE |
nice2 ssl mode |
|
BACKEND_URL |
nice2 hostname |
|
CYPRESS_BASE_URL |
nice2 hostname (officical Cypress env) |
|
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.
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 |
|
infobox |
Infobox |
|
export-item |
For different export items in the export action |
|
communication |
For different communication items in the communication action |
|
action |
For the different action groups like new, delete, output, etc. |
|
action-item |
For the different actions |
|
list-row |
Row in the table. Use the Entity-Id as the name |
|
header-cell and list-cell |
Are used in the tables. The name should be the relation or field name. |
|
form-field |
Input fields in the admin. The name should be the relation or the field name. |
|
box |
For the boxes in the detail-form |
|
admin-menuitem |
For the items in the admin menu |
|
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¶
Restore DB from existing DB dump (create empty DB when no dump is available)
Run DB refactoring
Run Nice2
Initialize DB
Crate Tocco User and API Key for Cypress (See Environment variables)
Create DB dump
Test Run¶
Empty DB
Forcefully restore DB from existing DB dump (created on nice2 start up)
Seed DB via REST API
Login
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
|
Opens BundleAnalyzerPlugin to investigate the bundle sizes. |
|
To enable an alternative backend. |