Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
ea6a04c
exit is now error code 1
tim-fabian May 1, 2025
7a52ba3
increased timeout for 'generatePage for navbar'
tim-fabian May 1, 2025
fd3b4ea
Added docker pulls for images used in tests
tim-fabian May 1, 2025
7019fca
increased max fast time
tim-fabian May 1, 2025
83ace21
Improved logging for stringify and parse
tim-fabian May 1, 2025
71d10aa
added exitGracefully function
tim-fabian May 1, 2025
2cc037d
Increased test timeout for adding nest and loopback with database cre…
tim-fabian May 1, 2025
30548a9
improved error logging
tim-fabian May 1, 2025
15ea005
improved error logging
tim-fabian May 1, 2025
e2c88b4
mock create mail service
tim-fabian May 1, 2025
ff32753
mock create mail service
tim-fabian May 1, 2025
8681c62
mock create admin files
tim-fabian May 1, 2025
8d551a3
added new max time value
tim-fabian May 1, 2025
2c645b6
increased add-angular timeout
tim-fabian May 1, 2025
0e650da
Merge pull request #104 from Service-Soft/101-register-default-loopba…
tim-fabian May 1, 2025
b303084
removed runInBand for tests
tim-fabian May 1, 2025
ecc2a30
increased down command time
tim-fabian May 1, 2025
0ba768f
increased list command timeout
tim-fabian May 1, 2025
ad844c2
Merge pull request #106 from Service-Soft/105-improve-test-performance
tim-fabian May 1, 2025
d56691d
added env environment variable, added stage, added public env, setup …
tim-fabian May 3, 2025
0c424e1
updated docs
tim-fabian May 3, 2025
42d5605
Merge pull request #108 from Service-Soft/97-add-new-environment-type…
tim-fabian May 3, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@ jobs:
test:
runs-on: ubuntu-latest
steps:
-
name: Set up Docker Compose
uses: docker/setup-compose-action@v1
- uses: docker/setup-compose-action@v1
- uses: actions/checkout@v4
- run: docker pull adminer
- run: docker pull postgres
- run: npm i -g @angular/cli@18 @loopback/cli@6 @nestjs/cli@11
- run: npm ci
- run: npm run build
- run: npm run test
26 changes: 19 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ The projects that can be added to a Monux monorepo also provide a lot of functio
- [Handling initial database content](#handling-initial-database-content)
- [How do they work?](#how-do-they-work)
- [Starting prod locally](#starting-prod-locally)
- [Starting in staging environment](#starting-in-staging-environment)
- [Starting in production](#starting-in-production)
- [Global Management of Monorepos](#global-management-of-monorepos)
- [Supported project types](#supported-project-types)
Expand Down Expand Up @@ -140,19 +141,21 @@ Monux provides a way to safely handle type safe environment variables. A lot of
The system supports two kinds of environment variables, <b>static</b> and <b>calculated</b>.

### Static environment variables
Static variables work by having a global `.env`-file which contains all the static variables of all projects in the monorepo. The cli provides a command `mx prepare`, which validates the content of the `.env`-file based on the `StaticGlobalEnvironment` schema type defined in the `global-environment.model.ts`-file.
Static variables work by having a global `.env`-file (**NOT** checked into git) and a global `.env.public`-file (checked into git), which contain all the static variables of all projects in the monorepo. The cli provides a command `mx prepare`, which validates the content of both these files based on the `StaticGlobalEnvironment` schema type defined in the `global-environment.model.ts`-file.

Each project where you actually want to use these variables has its own environment file, which is generated by the `mx prepare` command as well.<br>
How these environment files are generated depends on a `environment.model.ts`-file inside of each project. There you can define the keys of the global environment file that should be used by this specific project.<br>
That way it is possible to only have certain variables like an contact email-address be available to a website project, while certain other variables like a db-password are not.
<br>
Environment variables from both files can be used inside docker when you run the `mx up` command.

### Calculated environment variables
Working with static variables can sometimes be pretty tedious. This is especially true when you want to support different "modes" in which to launch your application (like we do with the different options for `mx up`).<br>
For example, if we defined the variables "api_base_url", "website_base_url" and "admin_base_url" all statically, we would need to manually fiddle with the `.env`-file anytime we switch between dev and local.<br>
To solve this, Monux implements calculated environment variables.

The schema type works exactly the same as with static variables. It's called `CalculatedGlobalEnvironment` and is also inside the `global-environment.model.ts`-file.<br>
But instead of parsing the values from the `.env`-file during the prepare step, calculated variables are created by calling a method defined in the `calculationSchemaFor`-record of the `global-environment.model.ts`-file:
But instead of parsing the values from the `.env`- and `.env.public`-file during the prepare step, calculated variables are created by calling a method defined in the `calculationSchemaFor`-record of the `global-environment.model.ts`-file:

```ts
/**
Expand Down Expand Up @@ -198,17 +201,21 @@ export type GlobalEnvironment = {
```

The model above is used to validate the environment variables we provide, so the current configuration validates:
- that both variables exist in the `.env`-file (you could change that by making them optional on the model)
- that both variables exist in the `.env`- or `.env.public`-file (you could change that by making them optional on the model)
- and that they are string values (you could also change their type to number which would validate that they are numbers etc.)

#### Add the actual values
To provide the actual values, we have to adjust the `.env`-file:
To provide the actual values, we have to adjust the `.env`- or `.env.public`-file:

`.env`
```
api_db_password=super_secret_password
```
`.env.public`
```
public_contact_email=public@email.address
```

#### Define the variables locally
Now that we have that, we need to define the variables that we want to use in each project where they are needed. We can do that by adjusting the respective environment.model.ts of these projects.

Expand Down Expand Up @@ -273,7 +280,7 @@ Whenever you add a project that configures some sort of database a subfolder wit

When running the `mx prepare` command, these configuration files are used to generate startup scripts for the database inside of the databases init folder (databases/nameOfDb/init/actualInitFile).

What's nice about this is that these configuration files actually only reference the environment variable names instead of real values, so things like db credentials are only ever need to be provided in the .env file, which is excluded from the git repository by default.
What's nice about this is that these configuration files actually only reference the environment variable names instead of real values, so things like the concrete db credentials only ever need to be provided in the `.env`- file, which is excluded from the git repository by default.

Monux handles everything regarding mapping these variable names back to values automatically, so you don't have to worry about it at all.

Expand All @@ -282,12 +289,17 @@ Often times you want to test your project under production like constraints (eg.

For that, you can run `mx up` with the environment "local".

## Starting in staging environment
For staging servers Monux provides an extra environment.

The configuration is almost the same as for production (See below), with the difference that certain services have Basic Auth setup. That way someone randomly stumbling across your projects cannot eg. see the new design of a website before it is finalized.

## Starting in production
You can start the whole monorepo with running `mx up` and then selecting "prod" as the environment.

This will try to run the `mx prepare` command.<br>
The only info required by that command is inside the `.env`-file.<br>
Monux also validates the `.env`-file, so by continueously running the command you can fill it little by little and don't need to worry that you start your monorepo with invalid or missing environment variables.
The only info required by that command are inside the `.env`- and `.env.public`-files.<br>
Monux also validates these files, so by continueously running the command you can fill it little by little and don't need to worry that you start your monorepo with invalid or missing environment variables.

## Global Management of Monorepos
The Monux cli commands `mx up`, `mx down`, `mx ls` and `mx la` can be run globally. That way you don't have to open up a certain directory just to exit some services.
Expand Down
5 changes: 4 additions & 1 deletion cspell.words.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,7 @@ dts
nestjs
cloudflare
cldr
cldrjs
cldrjs
htpasswd
basicauth
usersfile
2 changes: 1 addition & 1 deletion jest.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const config = {
'^.+.tsx?$': ['ts-jest', {}]
},
setupFilesAfterEnv: ['<rootDir>/jest.setup.ts'],
bail: true,
bail: false,
modulePathIgnorePatterns: ['tmp'],
// coverage
collectCoverage: true,
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "monux-cli",
"version": "2.2.4",
"version": "2.3.0",
"license": "MIT",
"main": "index.js",
"engines": {
Expand Down Expand Up @@ -33,7 +33,7 @@
"start": "npm run build && cd sandbox && node ../dist/index.js",
"build": "tsc",
"clear": "rm -rf sandbox && mkdir sandbox && npm run start i",
"test": "jest --runInBand",
"test": "jest",
"lint": "eslint . --max-warnings=0",
"lint:fix": "eslint . --max-warnings=0 --fix",
"prepublishOnly": "npm i && npm run build"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import { faker } from '@faker-js/faker';

import { fakeUniqueString } from './fake-unique-string.function';
import { KeyValue } from '../../../types';
import { KeyValue } from '../../types';

export function fakeStringKeyValue(): KeyValue<string> {
return {
Expand Down
File renamed without changes.
12 changes: 9 additions & 3 deletions src/__testing__/mock/constants.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
/* eslint-disable jsdoc/require-jsdoc */
import { ANGULAR_JSON_FILE_NAME, ANGULAR_ROUTES_FILE_NAME, APP_CONFIG_FILE_NAME, APPS_DIRECTORY_NAME, DEV_DOCKER_COMPOSE_FILE_NAME, PROD_DOCKER_COMPOSE_FILE_NAME, ENV_FILE_NAME, ENVIRONMENT_MODEL_TS_FILE_NAME, ENVIRONMENT_TS_FILE_NAME, ESLINT_CONFIG_FILE_NAME, GLOBAL_ENVIRONMENT_MODEL_FILE_NAME, LIBS_DIRECTORY_NAME, PACKAGE_JSON_FILE_NAME, LOCAL_DOCKER_COMPOSE_FILE_NAME, WORKSPACE_FILE_NAME, BASE_TS_CONFIG_FILE_NAME } from '../../constants';
import { ANGULAR_JSON_FILE_NAME, ANGULAR_ROUTES_FILE_NAME, APP_CONFIG_FILE_NAME, APPS_DIRECTORY_NAME, DEV_DOCKER_COMPOSE_FILE_NAME, PROD_DOCKER_COMPOSE_FILE_NAME, ENV_FILE_NAME, ENVIRONMENT_MODEL_TS_FILE_NAME, ENVIRONMENT_TS_FILE_NAME, ESLINT_CONFIG_FILE_NAME, GLOBAL_ENVIRONMENT_MODEL_FILE_NAME, LIBS_DIRECTORY_NAME, PACKAGE_JSON_FILE_NAME, LOCAL_DOCKER_COMPOSE_FILE_NAME, WORKSPACE_FILE_NAME, BASE_TS_CONFIG_FILE_NAME, STAGE_DOCKER_COMPOSE_FILE_NAME, ENV_PUBLIC_FILE_NAME } from '../../constants';
import { OmitStrict } from '../../types';
import { getPath, Path } from '../../utilities';

export const MAX_ADD_TIME: number = 60000;
export const MAX_ADD_TIME: number = 90000;

export const MAX_GEN_CODE_TIME: number = 10000;

export const MAX_FAST_TIME: number = 300;
export const MAX_FAST_TIME: number = 1000;

export const MAX_BARELY_NOTICEABLE_TIME: number = 500;

export const MAX_INSTANT_TIME: number = 100;

Expand All @@ -18,6 +20,7 @@ export type MockConstants = {
readonly DOCKER_COMPOSE_YAML: Path,
readonly DEV_DOCKER_COMPOSE_YAML: Path,
readonly LOCAL_DOCKER_COMPOSE_YAML: Path,
readonly STAGE_DOCKER_COMPOSE_YAML: Path,
readonly ANGULAR_ESLINT_CONFIG_MJS: Path,
readonly ANGULAR_PACKAGE_JSON: Path,
readonly ANGULAR_APP_NAME: string,
Expand All @@ -36,6 +39,7 @@ export type MockConstants = {
readonly ROOT_PACKAGE_JSON: Path,
readonly TS_LIBRARY_NAME: string,
readonly ENV: Path,
readonly ENV_PUBLIC: Path,
readonly GLOBAL_ENV_MODEL: Path,
readonly GITHUB_WORKFLOW_DIR: Path,
readonly WORKSPACE_JSON: Path,
Expand Down Expand Up @@ -77,6 +81,7 @@ export function getMockConstants(projectName: string): MockConstants {
DOCKER_COMPOSE_YAML: getPath(PROJECT_DIR, PROD_DOCKER_COMPOSE_FILE_NAME),
DEV_DOCKER_COMPOSE_YAML: getPath(PROJECT_DIR, DEV_DOCKER_COMPOSE_FILE_NAME),
LOCAL_DOCKER_COMPOSE_YAML: getPath(PROJECT_DIR, LOCAL_DOCKER_COMPOSE_FILE_NAME),
STAGE_DOCKER_COMPOSE_YAML: getPath(PROJECT_DIR, STAGE_DOCKER_COMPOSE_FILE_NAME),
ANGULAR_PACKAGE_JSON: getPath(ANGULAR_APP_DIR, PACKAGE_JSON_FILE_NAME),
ANGULAR_ESLINT_CONFIG_MJS: getPath(ANGULAR_APP_DIR, ESLINT_CONFIG_FILE_NAME),
ANGULAR_APP_NAME: ANGULAR_APP_NAME,
Expand All @@ -95,6 +100,7 @@ export function getMockConstants(projectName: string): MockConstants {
TS_LIBRARY_PACKAGE_JSON: getPath(TS_LIBRARY_DIR, PACKAGE_JSON_FILE_NAME),
ROOT_PACKAGE_JSON: getPath(PROJECT_DIR, PACKAGE_JSON_FILE_NAME),
ENV: getPath(PROJECT_DIR, ENV_FILE_NAME),
ENV_PUBLIC: getPath(PROJECT_DIR, ENV_PUBLIC_FILE_NAME),
GLOBAL_ENV_MODEL: getPath(PROJECT_DIR, GLOBAL_ENVIRONMENT_MODEL_FILE_NAME),
GITHUB_WORKFLOW_DIR: getPath(PROJECT_DIR, '.github', 'workflows'),
WORKSPACE_JSON: getPath(PROJECT_DIR, WORKSPACE_FILE_NAME),
Expand Down
37 changes: 37 additions & 0 deletions src/__testing__/mock/create-admin-files.mock.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { FsUtilities } from '../../encapsulation';
import { adminControllerContent } from '../../loopback/admin-controller.content';
import { adminModelContent } from '../../loopback/admin-model.content';
import { fullAdminModelContent } from '../../loopback/full-admin-model.content';
import { newAdminModelContent } from '../../loopback/new-admin-model.content';
import { Path, getPath } from '../../utilities';

// eslint-disable-next-line jsdoc/require-jsdoc
export async function createAdminFilesMock(root: string, dbName: string): Promise<void> {
const adminModelTs: Path = getPath(root, 'src', 'models', 'admin.model.ts');
await FsUtilities.createFile(adminModelTs, adminModelContent);
await FsUtilities.createFile(
getPath(root, 'src', 'models', 'roles.enum.ts'),
[
'export enum Roles {',
'\tADMIN = \'ADMIN\'',
'}'
]
);
await FsUtilities.createFile(
getPath(root, 'src', 'models', 'index.ts'),
[
'export * from \'./admin.model\';',
'export * from \'./roles.enum\';'
]
);

const adminRepositoryTs: Path = getPath(root, 'src', 'repositories', 'admin.repository.ts');
await FsUtilities.createFile(adminRepositoryTs, []);

const controllerPath: string = getPath(root, 'src', 'controllers');
await FsUtilities.createFile(getPath(controllerPath, 'admin', 'admin.controller.ts'), adminControllerContent(dbName));
await FsUtilities.updateFile(getPath(controllerPath, 'index.ts'), 'export * from \'./admin/admin.controller\';', 'append');

await FsUtilities.createFile(getPath(controllerPath, 'admin', 'new-admin.model.ts'), newAdminModelContent);
await FsUtilities.createFile(getPath(controllerPath, 'admin', 'full-admin.model.ts'), fullAdminModelContent);
}
8 changes: 8 additions & 0 deletions src/__testing__/mock/create-mail-service.mock.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { FsUtilities } from '../../encapsulation';
import { Path, getPath } from '../../utilities';

// eslint-disable-next-line jsdoc/require-jsdoc
export async function createMailServiceMock(root: string): Promise<void> {
const servicePath: Path = getPath(root, 'src', 'services', 'mail.service.ts');
await FsUtilities.createFile(servicePath, []);
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
/* eslint-disable jsdoc/require-jsdoc */
import { faker } from '@faker-js/faker';

import { fakeUniqueString } from './helpers';
import { CalculatedEnvVariable, EnvironmentVariableKey } from '../../env';
import { fakeUniqueString } from '../helpers';

export function fakeCalculatedEnvVariable(data?: Partial<CalculatedEnvVariable>): CalculatedEnvVariable {
const type: 'string' | 'number' = faker.helpers.arrayElement(['string', 'number']);
Expand Down
2 changes: 1 addition & 1 deletion src/__testing__/mock/fake-compose-service.function.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
/* eslint-disable jsdoc/require-jsdoc */
import { faker } from '@faker-js/faker';

import { fakeStringKeyValue, fakeUniqueString, fakeArray } from './helpers';
import { ComposePort, ComposeService } from '../../docker';
import { fakeStringKeyValue, fakeUniqueString, fakeArray } from '../helpers';

function fakeComposePort(): ComposePort {
return {
Expand Down
2 changes: 1 addition & 1 deletion src/__testing__/mock/fake-env-variable.function.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
/* eslint-disable jsdoc/require-jsdoc */
import { faker } from '@faker-js/faker';

import { fakeUniqueString } from './helpers';
import { EnvironmentVariableKey, EnvVariable } from '../../env';
import { fakeUniqueString } from '../helpers';

export function fakeEnvVariable(data?: Partial<EnvVariable>): EnvVariable {
const type: 'string' | 'number' = faker.helpers.arrayElement(['string', 'number']);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
/* eslint-disable jsdoc/require-jsdoc */
import { faker } from '@faker-js/faker';

import { fakeArray, fakeStringRecord, fakeUniqueString } from './helpers';
import { PackageJson } from '../../npm';
import { fakeArray, fakeStringRecord, fakeUniqueString } from '../helpers';

export function fakeUpdatePackageJsonData(): Partial<PackageJson> {
return {
Expand Down
18 changes: 16 additions & 2 deletions src/__testing__/mock/file-mock.utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@ export const defaultFilesToMock: (keyof FileMockConstants)[] = [
'WORKSPACE_JSON',
'BASE_TS_CONFIG_JSON',
'ENV',
'ENV_PUBLIC',
'GLOBAL_ENV_MODEL',
'ROOT_PACKAGE_JSON',
'DOCKER_COMPOSE_YAML',
'DEV_DOCKER_COMPOSE_YAML',
'LOCAL_DOCKER_COMPOSE_YAML'
'LOCAL_DOCKER_COMPOSE_YAML',
'STAGE_DOCKER_COMPOSE_YAML'
] as const;

export const defaultFoldersToMock: (keyof DirMockConstants)[] = [
Expand All @@ -33,6 +35,7 @@ export abstract class FileMockUtilities {
DOCKER_COMPOSE_YAML: this.createEmptyFile,
DEV_DOCKER_COMPOSE_YAML: this.createEmptyFile,
LOCAL_DOCKER_COMPOSE_YAML: this.createEmptyFile,
STAGE_DOCKER_COMPOSE_YAML: this.createEmptyFile,
ANGULAR_ESLINT_CONFIG_MJS: this.createEmptyFile,
ANGULAR_PACKAGE_JSON: this.createAngularPackageJson,
ANGULAR_APP_COMPONENT_TS: this.createAppComponentTsFile,
Expand All @@ -46,6 +49,7 @@ export abstract class FileMockUtilities {
TS_LIBRARY_PACKAGE_JSON: this.createEmptyFile,
ROOT_PACKAGE_JSON: this.createRootPackageJson,
ENV: this.createEnv,
ENV_PUBLIC: this.createEnvPublic,
GLOBAL_ENV_MODEL: this.createGlobalEnvModel,
WORKSPACE_JSON: WorkspaceUtilities.createConfig,
BASE_TS_CONFIG_JSON: TsConfigUtilities.createBaseTsConfig
Expand Down Expand Up @@ -201,6 +205,16 @@ export abstract class FileMockUtilities {
}

private static async createEnv(mockConstants: MockConstants): Promise<void> {
await FsUtilities.createFile(mockConstants.ENV, ['prod_root_domain=test.com', 'is_public=false']);
await FsUtilities.createFile(
mockConstants.ENV,
['basic_auth_user=user', 'basic_auth_password=password']
);
}

private static async createEnvPublic(mockConstants: MockConstants): Promise<void> {
await FsUtilities.createFile(
mockConstants.ENV_PUBLIC,
['prod_root_domain=test.com', 'stage_root_domain=test-staging.com']
);
}
}
4 changes: 3 additions & 1 deletion src/__testing__/mock/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,6 @@ export * from './fake-update-package-json-data.function';
export * from './fake-add-nav-element-config.function';
export * from './fake-env-variable.function';
export * from './fake-calculated-env-variable.function';
export * from './mock-inquire.function';
export * from './inquire.mock';
export * from './create-mail-service.mock';
export * from './create-admin-files.mock';
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import { BuiltInQuestion } from 'inquirer/dist/cjs/types/types';

// eslint-disable-next-line typescript/no-explicit-any
export function mockInquire(answers: Record<string, unknown>): (question: BuiltInQuestion) => Promise<any> {
export function inquireMock(answers: Record<string, unknown>): (question: BuiltInQuestion) => Promise<any> {
return (question: BuiltInQuestion) => {
if (typeof question.message !== 'string') {
throw new Error('Cannot mock questions with messages that are async functions.');
Expand Down
6 changes: 3 additions & 3 deletions src/angular/angular-utilities.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { getPath } from '../utilities';
const mockConstants: MockConstants = getMockConstants('angular-utilities');

let npmInstallMock: jest.SpiedFunction<typeof NpmUtilities.install>;
let cpExecSyncMock: jest.SpiedFunction<typeof CPUtilities.execSync>;
let cpExecSyncMock: jest.SpiedFunction<typeof CPUtilities.exec>;

describe('AngularUtilities', () => {
beforeEach(async () => {
Expand All @@ -26,7 +26,7 @@ describe('AngularUtilities', () => {
]
);
npmInstallMock = jest.spyOn(NpmUtilities, 'install').mockImplementation(async () => {});
cpExecSyncMock = jest.spyOn(CPUtilities, 'execSync').mockImplementation(() => {});
cpExecSyncMock = jest.spyOn(CPUtilities, 'exec').mockImplementation(async () => {});
});

test('addComponentImports', async () => {
Expand Down Expand Up @@ -255,7 +255,7 @@ describe('AngularUtilities', () => {
'',
'export const routes: NavRoute[] = NavUtilities.getAngularRoutes(navbarRows, footerRows, [notFoundRoute]);'
]);
}, MAX_GEN_CODE_TIME);
}, MAX_GEN_CODE_TIME * 2);

test('generatePage for footer', async () => {
await AngularUtilities.setupNavigation(mockConstants.ANGULAR_APP_DIR, mockConstants.ANGULAR_APP_NAME);
Expand Down
Loading
Loading