The ALLTHINGS app — based on react.js.
- Prerequisite
- Overview
- Redux
- Developer notes
- Tests
- Deploying
- Testing the legacy bundle in your evergreen browser
- Troubleshoot
- UI
As specified in the package.json file, the node engine must be >= 6.5.0 and the npm version must be >=3.0.0.
The best way to manage multiple active NodeJS versions is to use nvm. Please refer to its documentation.
"resolutions": {
"uglifyjs-webpack-plugin/uglify-es": "3.1.6"
}
We needed to pin the package uglify-es
to a specific version because of a bug that occured.
See: https://github.com/allthings/app/pull/1087
This needs to be revisited soon, to make sure we can get rid of this again.
yarn
Linux user don't need fsevents and should run the following command:
yarn --ignore-optional
yarn build
This will build 3 bundles:
- Server side build
- Client vendor build (
react
,redux
,glamor
, etc. seewebpack/dll/dll.base.config.js
) - Client side build (with webpack)
Server side code will land into dist
folder and client side code into public/static/js
.
yarn start
This will watch the file system for change inside the src
folder and trigger an incremental build.
After it was rebuilt the node container will be restarted so that the server side can serve the correct bundle.
Important: Webpack DLL is not run in an incremental build. This has to be done either manually by npm run webpack:dll
or a full build npm run build
.
If everything worked you can go to https://app.dev.allthings.me and see the app running.
If you are targeting the legacy bundle - by default only the modern one is built - append the legacy keyword:
yarn start legacy
If you want to deep dive into the content of the bundles in order to optimize them, set the following environment variable before performing a yarn build
:
export WEBPACK_REPORT=1
The reports will be generated and opened automatically.
To disable it run:
unset WEBPACK_REPORT
APP_DOMAIN="<your allthings app domain>" \
OAUTH_CLIENT_ID="<your oauth client id here>" \
yarn start:standalone
Then navigate to https://app.localhost/
Note: Since the standalone environment uses a self-signed SSL certificate, the first time running the standalone development environment you'll need to confirm an exception to the SSL certificate in your browser. Do this by opening the following two URLs in your browser:
open https://app.localhost/
open https://app-cdn.localhost/
Note 2: Your OAuth client must be valid in the Target API Environment and must be a "public" Client with Authorization Code grant allowed. If it's not a trusted Client, it also needs DPA and TOS fields filled for the User Authorization Screen.
Note 3: The App Domain must exist in the Target API Environment
Note 4: If the localhost subdomains don't resolve, you might try adding the following to your /etc/hosts
file.
127.0.0.1 app.localhost
127.0.0.1 app-cdn.localhost
127.0.0.1 app.staging.localhost
127.0.0.1 app.prerelease-magenta.localhost
One can point the App at different environments by using different hostnames:
API Environment | URL |
---|---|
Production | https://app.localhost/ |
Staging | https://app.staging.localhost/ |
Prerelease | https://app.prerelease-magenta.localhost/ |
components
are not connected to the store and only serve presentational purposecontainers
should connect to the store and render components passing datamicroapps
are accessible to logged in users and represent a self-contained unitwith a menu item and own color theme, e.g.Settings
pages
are located directly under the root node and are independent of any other part of the app.they can however be wrapped by containers if they need to be connected to the storeserver
is responsible for the server-side rendering of the appstore
comprises actions, reducers and the store configutils
act like internal libraries and offer functions that are used throughout different parts of the app
The basic workflow in this app is powered by redux, which basically consists of a store, actions and reducers.
Nothing too fancy, holds the state of the app.
To create one or multiple actions use createActions
. Should be placed in src/actions
const actions = createActions({
simpleAction (foo, bar) {
return { payload: { foo, bar } }
}
// ...
})
When called, this action will be dispatched automatically with the associated type (given by its name):
actions.simpleAction('Hello', 'World')
/*
This is what the dispatched object looks like:
{
type: 'simpleAction',
foo: 'Hello',
bar: 'World'
}
*/
An async action is recognized by returning a callback instead of an object.
Params given into the callback
Param | Type | Description |
---|---|---|
dispatch |
function | Dispatches actions. |
api |
object | A function to call the API (provided by the js-sdk ) |
state |
function | The current application state. |
const actions = createActions({
asyncLogin (user, pass) {
return async (dispatch, api, state) => {
dispatch({ status: 'pending' })
const response = await api({
path: 'api/some/endpoint',
params: {
foo: state.bar
}
})
if (response.status.code === 200) {
dispatch({ status: 'ok', payload: response.entity })
} else {
// Example for an error
dispatch({ status: 'error', payload: response.error })
}
}
}
})
const reducers = createReducers({
simpleAction (state, action) {
return {
...state,
}
},
asyncLogin (state, action) {
// action.status one of 'pending', 'ok' or 'error'
}
})
yarn lint
Whenever you create or edit a React component or any other JavaScript file, you must update or create a corresponding test file in the same directory.
By convention the test file should be named after the file's name with an additional .test.
part:
SomeDir
| - MyButton.jsx
| - MyButton.test.jsx
SomeOtherDir
| - utils.js
| - utils.test.js
To manually trigger the unit tests, run:
yarn test:unit
You can also use the corresponding watch task:
yarn watch:test:unit
The unit tests are performed using the Jest platform, please refer its documentation.
React component testing is based on the Enzyme testing utility, please refer to its documentation.
The use of snapshots generated by the toMatchSnapshot()
method is strongly encouraged. Those snapshots must be always commited as they are a very useful tool whenever you want to make sure your UI does not change unexpectedly
This is the default and preferred way of writting / running e2e tests. Whenever you have to refactor or create new specs, please use the new setup!
The exhaustive documentation can be found in the e2e repository.
K.I.S.S. principle is the golden rule here 📜.
A spec:
- should not be any longer than 100 loc, if not split it!
- should be purely declarative, easy to read. Do not introduce complex utility functions for the sake of making it cleaver, it should be easy to understand!
- should be testing one piece of functionality, not a complete section (e.g. create / edit / delete).
- should not test the back-end. The back-end has its own set of unit tests.
- should not rely on data you have created or modify in another spec. If you expect something to be there, you probably need the db-data dump to be adjusted to your need.
The specs are living in ./test/wdio/test/app/specs/
.
The specs are using webdriver i/o, please refer to its own documentation.
You can either use chrome
or firefox
directly without any additional setup (more browsers / devices are available, please check the e2e repository):
# Run all the specs against chrome and firefox.
yarn wdio
# Run one spec against chrome.
yarn wdio:chrome --spec custom-filter-creation
# Run one spec against firefox.
yarn wdio:firefox --spec custom-filter-creation
Getting Cannot start service geckodriver
/ Cannot start service chromedriver
?
cd ./test/wdio && docker-compose down -v
The e2e tests are written with Nightwatch.js.
New tests can be simply added by creating new spec files in the test/e2e/specs
directory.
In order to wait for an element before performing any kind of interaction (e.g. a click), you should use the following custom command:
browser
.waitForElementClickable(someElement)
.click(someElement)
Please note that the tests are clustered in four different directories (test/specs/app/pipeline-1
, test/specs/app/pipeline-2
, test/specs/app/pipeline-3
, test/specs/app/pipeline-4
) in order to get them running concurrently in the CI! They are organized in a way that the average execution time of each folder is almost similar.
yarn e2e
Unless npm run e2e
has been executed already, run the following command once:
yarn release-build
Next you'll be able to debug the e2e tests with the following command:
yarn e2e-vnc
yarn e2e-dev