Skip to content

Commit

Permalink
feat(BlueBase): Added reboot method
Browse files Browse the repository at this point in the history
  • Loading branch information
artalat committed Jul 21, 2019
1 parent ee0b796 commit a8abaf6
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 31 deletions.
98 changes: 86 additions & 12 deletions src/BlueBase.tsx
Expand Up @@ -17,9 +17,27 @@ import {
} from './registries';

import { MaybeRenderPropChildren } from './utils';
import React from 'react';
import systemFilters from './filters';

export interface BlueBaseProgress {
/**
* Has the app booted yet
*/
readonly booted: boolean;

/**
* Are we loading the app
*/
readonly loading: boolean;

/**
* Any errors occured while booting the app
*/
readonly error: any;
}

export type SetStateFn = (state: BlueBaseProgress) => Promise<void>;

export interface BootOptions {
/** Collection of assets to add in BlueBase's Asset Registry. */
assets: AssetCollection;
Expand Down Expand Up @@ -47,6 +65,21 @@ export interface BootOptions {
children?: MaybeRenderPropChildren<{ BB: BlueBase }>;
}

export interface BootOptionsInternal extends BootOptions {
onProgress?: SetStateFn;
reset?: boolean;
}

const emptyBootOptions: BootOptionsInternal = {
assets: {},
components: {},
configs: {},
filters: {},
fonts: {},
plugins: [],
themes: [],
};

export class BlueBase {
// APIs
public Analytics = new Analytics(this);
Expand All @@ -67,20 +100,57 @@ export class BlueBase {
// Flags
public booted = false;

private bootOptions: BootOptions = {
assets: {},
components: {},
configs: {},
filters: {},
fonts: {},
plugins: [],
themes: [],
};

public async boot(options?: Partial<BootOptions> & { children?: React.ReactNode }) {
private bootOptions: BootOptions = emptyBootOptions;

public async boot({ onProgress, ...options }: Partial<BootOptionsInternal> = {}) {
// Store onProgress for later use, even after boot finishes (i.e. in reboot, etc)
if (onProgress) {
this.onProgress = onProgress;
}

await this.onProgress({
booted: false,
error: null,
loading: true,
});

try {
await this.bootInternal(options);
await this.onProgress({
booted: this.booted,
error: null,
loading: false,
});
} catch (error) {
await this.onProgress({
booted: false,
error,
loading: false,
});
}

return this;
}

/**
* Performs a reset and boot.
*/
public async reboot(options?: BootOptionsInternal) {
return this.boot({ ...options, reset: true });
}

/**
* Main boot business logic
* @param param
*/
protected async bootInternal({ reset, ...options }: Partial<BootOptionsInternal> = {}) {
// Update boot options
this.bootOptions = { ...this.bootOptions, ...options };

if (reset === true) {
await this.Filters.run('bluebase.system.reset', this.bootOptions);
}

// Register basic filters here, so they can be used in boot
await this.Filters.registerNestedCollection(systemFilters);

Expand All @@ -92,4 +162,8 @@ export class BlueBase {

return this;
}

private onProgress: SetStateFn = async () => {
return;
}
}
19 changes: 5 additions & 14 deletions src/OfflineComponents/BlueBaseApp/BlueBaseApp.tsx
@@ -1,4 +1,4 @@
import { BlueBase, BootOptions } from '../../BlueBase';
import { BlueBase, BlueBaseProgress, BootOptions } from '../../BlueBase';
import {
BlueBaseAppError,
BlueBaseAppErrorProps,
Expand Down Expand Up @@ -80,20 +80,11 @@ export class BlueBaseApp extends React.Component<BlueBaseAppProps, BlueBaseAppSt

async componentDidMount() {
const BB = this.state.BB;
BB.boot({ ...this.props, onProgress: this.onProgress });
}

try {
await BB.boot(this.props);
this.setState({
booted: BB.booted,
loading: false,
});
} catch (error) {
this.setState({
booted: false,
error,
loading: false,
});
}
onProgress = async (params: BlueBaseProgress) => {
await this.setState(params);
}

componentDidCatch(error: Error | null) {
Expand Down
20 changes: 16 additions & 4 deletions src/OfflineComponents/BlueBaseApp/__tests__/BlueBaseApp.test.tsx
@@ -1,9 +1,11 @@
import { waitForElement, waitForState } from 'enzyme-async-helpers';

import { BlueBase } from '../../../BlueBase';
import { BlueBaseApp } from '../BlueBaseApp';
import { BlueBaseAppError } from '../../BlueBaseAppError';
import React from 'react';
import { Text } from 'react-native';
import { mount } from 'enzyme';
import { waitForState } from 'enzyme-async-helpers';

declare const global: any;

Expand Down Expand Up @@ -73,12 +75,14 @@ describe('BlueBaseApp', () => {
test(`should render error state when boot throws an error`, async () => {
const BB = new BlueBase();
BB.Configs.setValue('development', true);
BB.boot = () => {
(BB as any).bootInternal = () => {
throw Error('Boot Error!');
};

const wrapper = mount(<BlueBaseApp BB={BB} />);

await waitForElement(wrapper, BlueBaseAppError);

// expect(wrapper).toMatchSnapshot();
expect(
wrapper
Expand Down Expand Up @@ -149,6 +153,8 @@ describe('BlueBaseApp', () => {
await waitForState(wrapper as any, (state: any) => state.loading === false);
wrapper.update();

await waitForElement(wrapper, BlueBaseAppError);

// expect(wrapper).toMatchSnapshot();
expect(
wrapper
Expand Down Expand Up @@ -184,6 +190,8 @@ describe('BlueBaseApp', () => {
await waitForState(wrapper as any, (state: any) => state.loading === false);
wrapper.update();

await waitForElement(wrapper, BlueBaseAppError);

// expect(wrapper).toMatchSnapshot();
expect(
wrapper
Expand All @@ -202,12 +210,14 @@ describe('BlueBaseApp', () => {
// tslint:disable-next-line: max-line-length
test(`should render error state with actual error message when development config is undefined, && isProduction is false`, async () => {
const BB = new BlueBase();
BB.boot = () => {
(BB as any).bootInternal = () => {
throw Error('Boot Error!');
};

const wrapper = mount(<BlueBaseApp BB={BB} />);

await waitForElement(wrapper, BlueBaseAppError);

// expect(wrapper).toMatchSnapshot();
expect(
wrapper
Expand All @@ -226,14 +236,16 @@ describe('BlueBaseApp', () => {
// tslint:disable-next-line: max-line-length
test(`should render error state with custom error message when development config is undefined, && isProduction is true`, async () => {
const BB = new BlueBase();
BB.boot = () => {
(BB as any).bootInternal = () => {
throw Error('Boot Error!');
};

global.process.env.NODE_ENV = 'production';

const wrapper = mount(<BlueBaseApp BB={BB} />);

await waitForElement(wrapper, BlueBaseAppError);

// expect(wrapper).toMatchSnapshot();
expect(
wrapper
Expand Down
22 changes: 21 additions & 1 deletion src/filters/boot.ts
Expand Up @@ -6,7 +6,7 @@ export const boot: FilterNestedCollection = {
'bluebase.boot': [
{
key: 'bluebase-boot-default',
priority: 5,
priority: 3,

// tslint:disable-next-line:object-literal-sort-keys
value: async (bootOptions: BootOptions, _ctx: {}, BB: BlueBase) => {
Expand Down Expand Up @@ -48,4 +48,24 @@ export const boot: FilterNestedCollection = {
},
},
],

'bluebase.system.reset': [
{
key: 'bluebase-reset-default',
priority: 3,

// tslint:disable-next-line:object-literal-sort-keys
value: async (bootOptions: BootOptions, _ctx: {}, BB: BlueBase) => {
BB.Assets.clear();
BB.Components.clear();
BB.Configs.clear();
BB.Filters.clear();
BB.Fonts.clear();
BB.Plugins.clear();
BB.Themes.clear();

return bootOptions;
},
},
],
};

0 comments on commit a8abaf6

Please sign in to comment.