From 1e4ff99183b6cf8f68dca7237105bc72e2f8c99e Mon Sep 17 00:00:00 2001 From: Preston Lamb Date: Tue, 21 Sep 2021 15:37:56 -0600 Subject: [PATCH 1/6] fix README --- libs/runtime-config-loader/README.md | 31 +++++++++++++++++++++---- libs/runtime-config-loader/package.json | 2 +- 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/libs/runtime-config-loader/README.md b/libs/runtime-config-loader/README.md index 29a9bba..e9ec7a0 100644 --- a/libs/runtime-config-loader/README.md +++ b/libs/runtime-config-loader/README.md @@ -1,7 +1,30 @@ -# runtime-config-loader +# Angular Runtime Configuration Loader -This library was generated with [Nx](https://nx.dev). +Most applications require certain configuration values that can be changed at runtime of the app. The `environment.ts` files in an Angular application technically work for setting configuration values in an app, but those are buildtime configuration values. This means that they are set when the application is built, and can't be changed unless the app is built again. -## Running unit tests +## Overview -Run `nx test runtime-config-loader` to execute the unit tests. +This library provides an easy way to load a JSON file with configuration values or make an HTTP GET call to an API endpoint that returns those values. You can then use that configuration throughout the application. The default location of the JSON file is in the `assets` folder, at `./assets/config.json`. When the service loads the file, it stores that configuration object in a local variable which can be accessed via the `getConfig()` and `getConfigObjectKey(key: string)` methods. `getConfig` returns the entire configuration object; `getConfigObjectKey(key: string)` returns part of the configuration object, namely the part defined by the key passed in. In some cases, the `config.json` is not finished loading before other modules/services are, so the above methods will return null. If that is the case, subscribe to the `configSubject` and access the configuration object that way. + +## How to Implement + +In your `app.module.ts` file, add the following to the `@NgModule` decorator: + +```ts +imports: [..., RuntimeConfigLoaderModule, ...], +``` + +That's it; it's that simple. In the `RuntimeConfigLoaderModule`, the `APP_INITIALIZER` token is used to run a function which loads the configuration from a file or an API endpoint that can be used throughout the application. + +If you implement the library exactly as it is above, the configuration file needs to be in the `./assets/config.json` location as mentioned above. If you'd like to load the file from a different location, provide that location in the `.forRoot()` method when importing the `RuntimeConfigLoaderModule`: + +```js +imports: [ + ..., + RuntimeConfigLoaderModule.forRoot( + { configUrl: './path/to/config/config.json' } + ), + ...] +``` + +Make sure that the path you provide here is accessible by the Angular application, meaning that the file is somewhere the app can load it. In my opinion, the `assets` folder is the easiest place to work from. diff --git a/libs/runtime-config-loader/package.json b/libs/runtime-config-loader/package.json index 26a7ee4..4fb1a2f 100644 --- a/libs/runtime-config-loader/package.json +++ b/libs/runtime-config-loader/package.json @@ -1,6 +1,6 @@ { "name": "runtime-config-loader", - "version": "4.0.0", + "version": "4.0.1", "author": { "email": "preston.j.lamb@gmail.com", "name": "Preston Lamb", From fe9acf4c0769d79af1922e0040690534b49506bd Mon Sep 17 00:00:00 2001 From: Preston Lamb Date: Tue, 21 Sep 2021 21:24:00 -0600 Subject: [PATCH 2/6] feat: allow multiple file paths to be provided Multiple file paths can now be passed, and config will be loaded from all paths and then combined into a single object Resolves #2 --- .../runtime-config-loader.service.spec.ts | 170 +++++++++++++----- .../runtime-config-loader.service.ts | 30 +++- .../src/lib/runtime-config.ts | 2 +- 3 files changed, 153 insertions(+), 49 deletions(-) diff --git a/libs/runtime-config-loader/src/lib/runtime-config-loader/runtime-config-loader.service.spec.ts b/libs/runtime-config-loader/src/lib/runtime-config-loader/runtime-config-loader.service.spec.ts index 6611004..7b21185 100644 --- a/libs/runtime-config-loader/src/lib/runtime-config-loader/runtime-config-loader.service.spec.ts +++ b/libs/runtime-config-loader/src/lib/runtime-config-loader/runtime-config-loader.service.spec.ts @@ -6,55 +6,141 @@ import { RuntimeConfigLoaderService } from './runtime-config-loader.service'; describe('RuntimeConfigLoaderService', () => { let service: RuntimeConfigLoaderService; - let mockConfig: RuntimeConfig = { + let mockSingleConfig: RuntimeConfig = { configUrl: './test-config.json', }; - let mockConfigData = { + let mockDoubleConfig: RuntimeConfig = { + configUrl: ['./test-config.json', './test-config2.json'], + }; + let mockConfigData1 = { apiUrl: 'https://test-api.com', }; + let mockConfigData2 = { + apiUrl: 'https://test-2-api.com', + appName: 'App Name 2', + }; let mockHttpService: any; - beforeEach(() => { - mockHttpService = { get: null } as any as HttpClient; - service = new RuntimeConfigLoaderService(mockHttpService, mockConfig); - }); + describe('Single Config URL', () => { + beforeEach(() => { + mockHttpService = { get: null } as any as HttpClient; + service = new RuntimeConfigLoaderService( + mockHttpService, + mockSingleConfig + ); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); + + it( + 'should load the config object', + waitForAsync(() => { + mockHttpService.get = jest + .fn() + .mockReturnValue(of(mockConfigData1)); + service.loadConfig().subscribe(); - it('should be created', () => { - expect(service).toBeTruthy(); + const config = service.getConfig(); + expect(config).toStrictEqual(mockConfigData1); + }) + ); + + it( + 'should return the key from the config object', + waitForAsync(() => { + mockHttpService.get = jest + .fn() + .mockReturnValue(of(mockConfigData1)); + service.loadConfig().subscribe(); + + const configKey = service.getConfigObjectKey('apiUrl'); + expect(configKey).toStrictEqual(mockConfigData1.apiUrl); + }) + ); + + it( + 'should handle a load error', + waitForAsync(() => { + mockHttpService.get = jest + .fn() + .mockReturnValue(throwError('Test Error')); + service.loadConfig().subscribe(); + + const config = service.getConfig(); + expect(config).toStrictEqual(null); + }) + ); }); - it( - 'should load the config object', - waitForAsync(() => { - mockHttpService.get = jest.fn().mockReturnValue(of(mockConfigData)); - service.loadConfig().subscribe(); - - const config = service.getConfig(); - expect(config).toStrictEqual(mockConfigData); - }) - ); - - it( - 'should return the key from the config object', - waitForAsync(() => { - mockHttpService.get = jest.fn().mockReturnValue(of(mockConfigData)); - service.loadConfig().subscribe(); - - const configKey = service.getConfigObjectKey('apiUrl'); - expect(configKey).toStrictEqual(mockConfigData.apiUrl); - }) - ); - - it( - 'should handle a load error', - waitForAsync(() => { - mockHttpService.get = jest - .fn() - .mockReturnValue(throwError('Test Error')); - service.loadConfig().subscribe(); - - const config = service.getConfig(); - expect(config).toStrictEqual(null); - }) - ); + describe('Double Config URL', () => { + beforeEach(() => { + mockHttpService = { get: null } as any as HttpClient; + service = new RuntimeConfigLoaderService( + mockHttpService, + mockDoubleConfig + ); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); + + it( + 'should load the config object from both sources', + waitForAsync(() => { + mockHttpService.get = jest + .fn() + .mockReturnValueOnce(of(mockConfigData1)) + .mockReturnValueOnce(of(mockConfigData2)); + service.loadConfig().subscribe(); + + const config = service.getConfig(); + expect(config).toStrictEqual(mockConfigData2); + }) + ); + + it( + 'should return the key from the config object after combining both sources', + waitForAsync(() => { + mockHttpService.get = jest + .fn() + .mockReturnValueOnce(of(mockConfigData1)) + .mockReturnValueOnce(of(mockConfigData2)); + service.loadConfig().subscribe(); + + const configKey = service.getConfigObjectKey('apiUrl'); + expect(configKey).toStrictEqual(mockConfigData2.apiUrl); + }) + ); + + it( + 'should handle a load error when the first file fails', + waitForAsync(() => { + mockHttpService.get = jest + .fn() + .mockReturnValueOnce(throwError('Test Error')) + .mockReturnValueOnce(of(mockConfigData2)); + service.loadConfig().subscribe(); + + const config = service.getConfig(); + expect(config).toStrictEqual(null); + }) + ); + + it( + 'should handle a load error when the second file fails', + waitForAsync(() => { + mockHttpService.get = jest + .fn() + .mockReturnValueOnce(of(mockConfigData1)) + .mockReturnValueOnce(throwError('Test Error')); + service.loadConfig().subscribe(); + + const config = service.getConfig(); + expect(config).toStrictEqual(null); + }) + ); + }); }); diff --git a/libs/runtime-config-loader/src/lib/runtime-config-loader/runtime-config-loader.service.ts b/libs/runtime-config-loader/src/lib/runtime-config-loader/runtime-config-loader.service.ts index 8daac4b..1362d81 100644 --- a/libs/runtime-config-loader/src/lib/runtime-config-loader/runtime-config-loader.service.ts +++ b/libs/runtime-config-loader/src/lib/runtime-config-loader/runtime-config-loader.service.ts @@ -1,12 +1,12 @@ import { HttpClient } from '@angular/common/http'; import { Injectable, Optional } from '@angular/core'; import { RuntimeConfig } from '../runtime-config'; -import { Observable, of, Subject } from 'rxjs'; -import { catchError, tap } from 'rxjs/operators'; +import { forkJoin, Observable, of, Subject, zip } from 'rxjs'; +import { catchError, take, tap } from 'rxjs/operators'; @Injectable() export class RuntimeConfigLoaderService { - private configUrl: string = './assets/config.json'; + private configUrl: string | string[] = './assets/config.json'; private configObject: any = null; public configSubject: Subject = new Subject(); @@ -17,9 +17,23 @@ export class RuntimeConfigLoaderService { } loadConfig(): Observable { - return this._http.get(this.configUrl).pipe( - tap((configData: any) => { - this.configObject = configData; + const urls: string[] = Array.isArray(this.configUrl) + ? this.configUrl + : [this.configUrl]; + + const observables: Observable[] = urls.map((url) => + this.makeHttpCall(url) + ); + + return forkJoin(observables).pipe( + tap((configDataArray: any[]) => { + this.configObject = configDataArray.reduce( + (acc, configData) => { + return { ...acc, ...configData }; + }, + {} + ); + this.configSubject.next(this.configObject); }), catchError((err: any) => { @@ -31,6 +45,10 @@ export class RuntimeConfigLoaderService { ); } + private makeHttpCall(url: string): Observable { + return this._http.get(url).pipe(take(1)); + } + getConfig() { return this.configObject; } diff --git a/libs/runtime-config-loader/src/lib/runtime-config.ts b/libs/runtime-config-loader/src/lib/runtime-config.ts index aaeafc0..d39f91b 100644 --- a/libs/runtime-config-loader/src/lib/runtime-config.ts +++ b/libs/runtime-config-loader/src/lib/runtime-config.ts @@ -1,5 +1,5 @@ export class RuntimeConfig { - configUrl: string; + configUrl: string | string[]; constructor(obj: any = {}) { this.configUrl = obj.configUrl || './assets/config.json'; From b351cf38c0469c231e9e3734b04971ec025e217d Mon Sep 17 00:00:00 2001 From: Preston Lamb Date: Tue, 21 Sep 2021 21:34:09 -0600 Subject: [PATCH 3/6] chore: increment version and update README --- libs/runtime-config-loader/README.md | 34 ++++++++++++++++++++++--- libs/runtime-config-loader/package.json | 2 +- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/libs/runtime-config-loader/README.md b/libs/runtime-config-loader/README.md index e9ec7a0..59ec41e 100644 --- a/libs/runtime-config-loader/README.md +++ b/libs/runtime-config-loader/README.md @@ -4,7 +4,7 @@ Most applications require certain configuration values that can be changed at ru ## Overview -This library provides an easy way to load a JSON file with configuration values or make an HTTP GET call to an API endpoint that returns those values. You can then use that configuration throughout the application. The default location of the JSON file is in the `assets` folder, at `./assets/config.json`. When the service loads the file, it stores that configuration object in a local variable which can be accessed via the `getConfig()` and `getConfigObjectKey(key: string)` methods. `getConfig` returns the entire configuration object; `getConfigObjectKey(key: string)` returns part of the configuration object, namely the part defined by the key passed in. In some cases, the `config.json` is not finished loading before other modules/services are, so the above methods will return null. If that is the case, subscribe to the `configSubject` and access the configuration object that way. +This library provides an easy way to load one or more JSON files with configuration values or make one or more HTTP GET calls to an API endpoint that returns those values. The config objects that are returned from the call(s) will be combined into a single configuration object. You can then use that configuration throughout the application. The default location of the JSON file is in the `assets` folder, at `./assets/config.json`. When the service loads the file, it stores that configuration object in a local variable which can be accessed via the `getConfig()` and `getConfigObjectKey(key: string)` methods. `getConfig` returns the entire configuration object; `getConfigObjectKey(key: string)` returns part of the configuration object, namely the part defined by the key passed in. In some cases, the `config.json` is not finished loading before other modules/services are, so the above methods will return null. If that is the case, subscribe to the `configSubject` and access the configuration object that way. ## How to Implement @@ -18,7 +18,7 @@ That's it; it's that simple. In the `RuntimeConfigLoaderModule`, the `APP_INITIA If you implement the library exactly as it is above, the configuration file needs to be in the `./assets/config.json` location as mentioned above. If you'd like to load the file from a different location, provide that location in the `.forRoot()` method when importing the `RuntimeConfigLoaderModule`: -```js +```ts imports: [ ..., RuntimeConfigLoaderModule.forRoot( @@ -27,4 +27,32 @@ imports: [ ...] ``` -Make sure that the path you provide here is accessible by the Angular application, meaning that the file is somewhere the app can load it. In my opinion, the `assets` folder is the easiest place to work from. +If you want to load multiple files, the value of `configUrl` should be an array of strings: + +```ts +imports: [ + ..., + RuntimeConfigLoaderModule.forRoot( + { configUrl: ['./path/to/config/config-1.json', './path/to/config/config-2.json'] } + ), + ...] +``` + +> Make sure that the path(s) you provide here is accessible by the Angular application, meaning that the file is somewhere the app can load it. In my opinion, the `assets` folder is the easiest place to work from. + +## Multiple Config Paths + +One reason you may want to load multiple configuration objects is so that you can set the configuration on your machine without affecting anyone else. For example, you could have a `local.config.json` file that is not included in source control. Some of the values in that file would overwrite the values in a config file that everyone can use. Another use case is that some config values don't change between environments, and some do. The ones that don't change could go in one file, the ones that do change could go in a second file. Each developer/environment can provide the second file with values they want or need. + +It's important to know that if an attribute is repeated in two configuration files, the latest value is kept. So, let's say you have `apiUrl` in both files, `config-1.json` and `config-2.json`. Let's assume the files are passed in to the `forRoot` method like this: + +```ts +imports: [ + ..., + RuntimeConfigLoaderModule.forRoot( + { configUrl: ['./path/to/config/config-1.json', './path/to/config/config-2.json'] } + ), + ...] +``` + +In this case, the `apiUrl` value from `config-2.json` will override the value from `config-1.json`. diff --git a/libs/runtime-config-loader/package.json b/libs/runtime-config-loader/package.json index 4fb1a2f..0b2c194 100644 --- a/libs/runtime-config-loader/package.json +++ b/libs/runtime-config-loader/package.json @@ -1,6 +1,6 @@ { "name": "runtime-config-loader", - "version": "4.0.1", + "version": "4.1.0", "author": { "email": "preston.j.lamb@gmail.com", "name": "Preston Lamb", From 8cb3a9a83cf4d2484873d68943eefb42b9cd13b0 Mon Sep 17 00:00:00 2001 From: Preston Lamb Date: Tue, 21 Sep 2021 21:34:31 -0600 Subject: [PATCH 4/6] chore: update root README --- README.md | 122 ++++++++++++++++++------------------------------------ 1 file changed, 41 insertions(+), 81 deletions(-) diff --git a/README.md b/README.md index 7fd9d03..59ec41e 100644 --- a/README.md +++ b/README.md @@ -1,98 +1,58 @@ -# RuntimeConfigLoader +# Angular Runtime Configuration Loader -This project was generated using [Nx](https://nx.dev). +Most applications require certain configuration values that can be changed at runtime of the app. The `environment.ts` files in an Angular application technically work for setting configuration values in an app, but those are buildtime configuration values. This means that they are set when the application is built, and can't be changed unless the app is built again. -

+## Overview -🔎 **Smart, Extensible Build Framework** +This library provides an easy way to load one or more JSON files with configuration values or make one or more HTTP GET calls to an API endpoint that returns those values. The config objects that are returned from the call(s) will be combined into a single configuration object. You can then use that configuration throughout the application. The default location of the JSON file is in the `assets` folder, at `./assets/config.json`. When the service loads the file, it stores that configuration object in a local variable which can be accessed via the `getConfig()` and `getConfigObjectKey(key: string)` methods. `getConfig` returns the entire configuration object; `getConfigObjectKey(key: string)` returns part of the configuration object, namely the part defined by the key passed in. In some cases, the `config.json` is not finished loading before other modules/services are, so the above methods will return null. If that is the case, subscribe to the `configSubject` and access the configuration object that way. -## Quick Start & Documentation +## How to Implement -[Nx Documentation](https://nx.dev/angular) +In your `app.module.ts` file, add the following to the `@NgModule` decorator: -[10-minute video showing all Nx features](https://nx.dev/getting-started/intro) +```ts +imports: [..., RuntimeConfigLoaderModule, ...], +``` -[Interactive Tutorial](https://nx.dev/tutorial/01-create-application) +That's it; it's that simple. In the `RuntimeConfigLoaderModule`, the `APP_INITIALIZER` token is used to run a function which loads the configuration from a file or an API endpoint that can be used throughout the application. -## Adding capabilities to your workspace +If you implement the library exactly as it is above, the configuration file needs to be in the `./assets/config.json` location as mentioned above. If you'd like to load the file from a different location, provide that location in the `.forRoot()` method when importing the `RuntimeConfigLoaderModule`: -Nx supports many plugins which add capabilities for developing different types of applications and different tools. +```ts +imports: [ + ..., + RuntimeConfigLoaderModule.forRoot( + { configUrl: './path/to/config/config.json' } + ), + ...] +``` -These capabilities include generating applications, libraries, etc as well as the devtools to test, and build projects as well. +If you want to load multiple files, the value of `configUrl` should be an array of strings: -Below are our core plugins: +```ts +imports: [ + ..., + RuntimeConfigLoaderModule.forRoot( + { configUrl: ['./path/to/config/config-1.json', './path/to/config/config-2.json'] } + ), + ...] +``` -- [Angular](https://angular.io) - - `ng add @nrwl/angular` -- [React](https://reactjs.org) - - `ng add @nrwl/react` -- Web (no framework frontends) - - `ng add @nrwl/web` -- [Nest](https://nestjs.com) - - `ng add @nrwl/nest` -- [Express](https://expressjs.com) - - `ng add @nrwl/express` -- [Node](https://nodejs.org) - - `ng add @nrwl/node` +> Make sure that the path(s) you provide here is accessible by the Angular application, meaning that the file is somewhere the app can load it. In my opinion, the `assets` folder is the easiest place to work from. -There are also many [community plugins](https://nx.dev/community) you could add. +## Multiple Config Paths -## Generate an application +One reason you may want to load multiple configuration objects is so that you can set the configuration on your machine without affecting anyone else. For example, you could have a `local.config.json` file that is not included in source control. Some of the values in that file would overwrite the values in a config file that everyone can use. Another use case is that some config values don't change between environments, and some do. The ones that don't change could go in one file, the ones that do change could go in a second file. Each developer/environment can provide the second file with values they want or need. -Run `ng g @nrwl/angular:app my-app` to generate an application. +It's important to know that if an attribute is repeated in two configuration files, the latest value is kept. So, let's say you have `apiUrl` in both files, `config-1.json` and `config-2.json`. Let's assume the files are passed in to the `forRoot` method like this: -> You can use any of the plugins above to generate applications as well. +```ts +imports: [ + ..., + RuntimeConfigLoaderModule.forRoot( + { configUrl: ['./path/to/config/config-1.json', './path/to/config/config-2.json'] } + ), + ...] +``` -When using Nx, you can create multiple applications and libraries in the same workspace. - -## Generate a library - -Run `ng g @nrwl/angular:lib my-lib` to generate a library. - -> You can also use any of the plugins above to generate libraries as well. - -Libraries are shareable across libraries and applications. They can be imported from `@runtime-config-loader/mylib`. - -## Development server - -Run `ng serve my-app` for a dev server. Navigate to http://localhost:4200/. The app will automatically reload if you change any of the source files. - -## Code scaffolding - -Run `ng g component my-component --project=my-app` to generate a new component. - -## Build - -Run `ng build my-app` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build. - -## Running unit tests - -Run `ng test my-app` to execute the unit tests via [Jest](https://jestjs.io). - -Run `nx affected:test` to execute the unit tests affected by a change. - -## Running end-to-end tests - -Run `ng e2e my-app` to execute the end-to-end tests via [Cypress](https://www.cypress.io). - -Run `nx affected:e2e` to execute the end-to-end tests affected by a change. - -## Understand your workspace - -Run `nx dep-graph` to see a diagram of the dependencies of your projects. - -## Further help - -Visit the [Nx Documentation](https://nx.dev/angular) to learn more. - -## ☁ Nx Cloud - -### Distributed Computation Caching & Distributed Task Execution - -

- -Nx Cloud pairs with Nx in order to enable you to build and test code more rapidly, by up to 10 times. Even teams that are new to Nx can connect to Nx Cloud and start saving time instantly. - -Teams using Nx gain the advantage of building full-stack applications with their preferred framework alongside Nx’s advanced code generation and project dependency graph, plus a unified experience for both frontend and backend developers. - -Visit [Nx Cloud](https://nx.app/) to learn more. +In this case, the `apiUrl` value from `config-2.json` will override the value from `config-1.json`. From ffb1ce7b25d7f1e5e7fecd1d633ca5758b839b7f Mon Sep 17 00:00:00 2001 From: Preston Lamb Date: Tue, 21 Sep 2021 21:38:28 -0600 Subject: [PATCH 5/6] test: fix demo app test and create affected test command --- .../src/app/app.component.spec.ts | 36 ++---- nx.json | 80 ++++++------- package.json | 113 +++++++++--------- 3 files changed, 108 insertions(+), 121 deletions(-) diff --git a/apps/runtime-config-loader-demo/src/app/app.component.spec.ts b/apps/runtime-config-loader-demo/src/app/app.component.spec.ts index 51b037c..570c0c7 100644 --- a/apps/runtime-config-loader-demo/src/app/app.component.spec.ts +++ b/apps/runtime-config-loader-demo/src/app/app.component.spec.ts @@ -1,31 +1,17 @@ -import { TestBed } from '@angular/core/testing'; +import { RuntimeConfigLoaderService } from 'runtime-config-loader'; import { AppComponent } from './app.component'; describe('AppComponent', () => { - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [AppComponent], - }).compileComponents(); - }); + let app: AppComponent; + let mockRuntimeConfigService = {} as RuntimeConfigLoaderService; - it('should create the app', () => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.componentInstance; - expect(app).toBeTruthy(); - }); + beforeEach(() => { + app = new AppComponent( + mockRuntimeConfigService as RuntimeConfigLoaderService + ); + }); - it(`should have as title 'runtime-config-loader-demo'`, () => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.componentInstance; - expect(app.title).toEqual('runtime-config-loader-demo'); - }); - - it('should render title', () => { - const fixture = TestBed.createComponent(AppComponent); - fixture.detectChanges(); - const compiled = fixture.nativeElement as HTMLElement; - expect(compiled.querySelector('h1')?.textContent).toContain( - 'Welcome to runtime-config-loader-demo!' - ); - }); + it('should create the app', () => { + expect(app).toBeTruthy(); + }); }); diff --git a/nx.json b/nx.json index 82359af..d037e3b 100644 --- a/nx.json +++ b/nx.json @@ -1,42 +1,42 @@ { - "npmScope": "runtime-config-loader", - "affected": { - "defaultBase": "master" - }, - "implicitDependencies": { - "package.json": { - "dependencies": "*", - "devDependencies": "*" - }, - ".eslintrc.json": "*" - }, - "tasksRunnerOptions": { - "default": { - "runner": "@nrwl/nx-cloud", - "options": { - "cacheableOperations": ["build", "lint", "test", "e2e"], - "accessToken": "M2EyMjNlOWUtNjk1MC00Nzc1LWEyZWYtZWFiNDQ0ZjliNzY0fHJlYWQtd3JpdGU=" - } - } - }, - "targetDependencies": { - "build": [ - { - "target": "build", - "projects": "dependencies" - } - ] - }, - "projects": { - "runtime-config-loader": { - "tags": ["scope:shared", "type:util"] - }, - "runtime-config-loader-demo": { - "tags": [] - }, - "runtime-config-loader-demo-e2e": { - "tags": [], - "implicitDependencies": ["runtime-config-loader-demo"] - } - } + "npmScope": "runtime-config-loader", + "affected": { + "defaultBase": "main" + }, + "implicitDependencies": { + "package.json": { + "dependencies": "*", + "devDependencies": "*" + }, + ".eslintrc.json": "*" + }, + "tasksRunnerOptions": { + "default": { + "runner": "@nrwl/nx-cloud", + "options": { + "cacheableOperations": ["build", "lint", "test", "e2e"], + "accessToken": "M2EyMjNlOWUtNjk1MC00Nzc1LWEyZWYtZWFiNDQ0ZjliNzY0fHJlYWQtd3JpdGU=" + } + } + }, + "targetDependencies": { + "build": [ + { + "target": "build", + "projects": "dependencies" + } + ] + }, + "projects": { + "runtime-config-loader": { + "tags": ["scope:shared", "type:util"] + }, + "runtime-config-loader-demo": { + "tags": [] + }, + "runtime-config-loader-demo-e2e": { + "tags": [], + "implicitDependencies": ["runtime-config-loader-demo"] + } + } } diff --git a/package.json b/package.json index 4c28348..6e429dc 100644 --- a/package.json +++ b/package.json @@ -1,58 +1,59 @@ { - "name": "runtime-config-loader", - "version": "0.0.0", - "license": "MIT", - "scripts": { - "ng": "nx", - "postinstall": "node ./decorate-angular-cli.js && ngcc --properties es2015 browser module main", - "start": "nx serve", - "build": "nx build", - "test": "nx test" - }, - "private": true, - "dependencies": { - "@angular/animations": "^12.2.0", - "@angular/common": "^12.2.0", - "@angular/compiler": "^12.2.0", - "@angular/core": "^12.2.0", - "@angular/forms": "^12.2.0", - "@angular/platform-browser": "^12.2.0", - "@angular/platform-browser-dynamic": "^12.2.0", - "@angular/router": "^12.2.0", - "@nrwl/angular": "12.9.0", - "rxjs": "~6.6.0", - "tslib": "^2.0.0", - "zone.js": "~0.11.4" - }, - "devDependencies": { - "@angular-devkit/build-angular": "~12.2.0", - "@angular-eslint/eslint-plugin": "~12.3.0", - "@angular-eslint/eslint-plugin-template": "~12.3.0", - "@angular-eslint/template-parser": "~12.3.0", - "@angular/cli": "~12.2.0", - "@angular/compiler-cli": "^12.2.0", - "@angular/language-service": "^12.2.0", - "@nrwl/cli": "12.9.0", - "@nrwl/cypress": "12.9.0", - "@nrwl/eslint-plugin-nx": "12.9.0", - "@nrwl/jest": "12.9.0", - "@nrwl/linter": "12.9.0", - "@nrwl/nx-cloud": "latest", - "@nrwl/tao": "12.9.0", - "@nrwl/workspace": "12.9.0", - "@types/jest": "26.0.24", - "@types/node": "14.14.33", - "@typescript-eslint/eslint-plugin": "~4.28.3", - "@typescript-eslint/parser": "~4.28.3", - "cypress": "^8.3.0", - "eslint": "7.22.0", - "eslint-config-prettier": "8.1.0", - "eslint-plugin-cypress": "^2.10.3", - "jest": "27.0.3", - "jest-preset-angular": "9.0.7", - "ng-packagr": "^12.1.1", - "prettier": "^2.3.1", - "ts-jest": "27.0.3", - "typescript": "~4.3.5" - } + "name": "runtime-config-loader", + "version": "0.0.0", + "license": "MIT", + "scripts": { + "ng": "nx", + "postinstall": "node ./decorate-angular-cli.js && ngcc --properties es2015 browser module main", + "start": "nx serve", + "build": "nx build", + "test": "nx test", + "affected:test": "nx affected --target test --parallel --maxParallel 3" + }, + "private": true, + "dependencies": { + "@angular/animations": "^12.2.0", + "@angular/common": "^12.2.0", + "@angular/compiler": "^12.2.0", + "@angular/core": "^12.2.0", + "@angular/forms": "^12.2.0", + "@angular/platform-browser": "^12.2.0", + "@angular/platform-browser-dynamic": "^12.2.0", + "@angular/router": "^12.2.0", + "@nrwl/angular": "12.9.0", + "rxjs": "~6.6.0", + "tslib": "^2.0.0", + "zone.js": "~0.11.4" + }, + "devDependencies": { + "@angular-devkit/build-angular": "~12.2.0", + "@angular-eslint/eslint-plugin": "~12.3.0", + "@angular-eslint/eslint-plugin-template": "~12.3.0", + "@angular-eslint/template-parser": "~12.3.0", + "@angular/cli": "~12.2.0", + "@angular/compiler-cli": "^12.2.0", + "@angular/language-service": "^12.2.0", + "@nrwl/cli": "12.9.0", + "@nrwl/cypress": "12.9.0", + "@nrwl/eslint-plugin-nx": "12.9.0", + "@nrwl/jest": "12.9.0", + "@nrwl/linter": "12.9.0", + "@nrwl/nx-cloud": "latest", + "@nrwl/tao": "12.9.0", + "@nrwl/workspace": "12.9.0", + "@types/jest": "26.0.24", + "@types/node": "14.14.33", + "@typescript-eslint/eslint-plugin": "~4.28.3", + "@typescript-eslint/parser": "~4.28.3", + "cypress": "^8.3.0", + "eslint": "7.22.0", + "eslint-config-prettier": "8.1.0", + "eslint-plugin-cypress": "^2.10.3", + "jest": "27.0.3", + "jest-preset-angular": "9.0.7", + "ng-packagr": "^12.1.1", + "prettier": "^2.3.1", + "ts-jest": "27.0.3", + "typescript": "~4.3.5" + } } From 42b902f278424f99bf402c8ed8f79feb24b13af9 Mon Sep 17 00:00:00 2001 From: Preston Lamb Date: Tue, 21 Sep 2021 21:42:00 -0600 Subject: [PATCH 6/6] test: test with nested values --- .../runtime-config-loader.service.spec.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libs/runtime-config-loader/src/lib/runtime-config-loader/runtime-config-loader.service.spec.ts b/libs/runtime-config-loader/src/lib/runtime-config-loader/runtime-config-loader.service.spec.ts index 7b21185..09698fc 100644 --- a/libs/runtime-config-loader/src/lib/runtime-config-loader/runtime-config-loader.service.spec.ts +++ b/libs/runtime-config-loader/src/lib/runtime-config-loader/runtime-config-loader.service.spec.ts @@ -14,10 +14,16 @@ describe('RuntimeConfigLoaderService', () => { }; let mockConfigData1 = { apiUrl: 'https://test-api.com', + nestedObject: { + nested: 'value', + }, }; let mockConfigData2 = { apiUrl: 'https://test-2-api.com', appName: 'App Name 2', + nestedObject: { + nested: 'value 2', + }, }; let mockHttpService: any;