From d787a76adefd863042a75cb9eb95ffec38a39c4a Mon Sep 17 00:00:00 2001 From: Luxalpa Date: Wed, 3 Nov 2021 11:59:20 +0100 Subject: [PATCH] Reintroduce Laika component (#90) * Reintroduce Laika component * improved tests and added request delay * add disabled test also for hook --- CHANGELOG.md | 19 +++++++++++++ README.md | 46 ++++++++++++++++++++++++++++++- package.json | 2 +- src/component.test.tsx | 60 +++++++++++++++++++++++++++++++++++++++++ src/component.tsx | 34 +++++++++++++++++++++++ src/hook.test.tsx | 23 ++++++++++++---- src/index.ts | 7 ++--- src/mock/mockRequest.ts | 1 + src/utils.test.ts | 10 +++---- 9 files changed, 187 insertions(+), 15 deletions(-) create mode 100644 CHANGELOG.md create mode 100644 src/component.test.tsx create mode 100644 src/component.tsx diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..a3834e3 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,19 @@ +# Changelog + +## [1.1.0] - 2021-11-03 + +### Added + +- Re-added Laika component. It can now use the context as well. +- Added this changelog + +## [1.0.0] - 2021-11-02 + +### Changed + +- This release is a complete rewrite in TypeScript which replaces the Laika component with a hook that can also optionally read its values from a context. + +### Added + +- Context +- `useLaika` hook diff --git a/README.md b/README.md index 908ded9..b31c8fa 100644 --- a/README.md +++ b/README.md @@ -74,7 +74,35 @@ function SomeComponent() { } ``` -### getFeatureStatus +### Component + +```tsx +import React from 'react' +import { useLaika, Config, LaikaContext, Laika } from 'laika-react' +/* ... import your components ... */ + +const uri = 'https://laika.example.com' +const env = 'prod' + +function SomeComponent() { + return ( +
+ } + onFalse={} + /> +
+ ) +} +``` + + + +### Promise (getFeatureStatus) ```ts import { getFeatureStatus } from 'laika-react' @@ -131,6 +159,22 @@ Parameter | Function `cacheTimeout` | The time how long a requested flag should be cached (default: 1.5 minutes).
The flags and cache timestamps are saved in localstorage. ***Return values*** | Returns an array with 2 entries:
1. `state`: The current state of the flag (`true` or `false`, defaults to `false` while the request is still resolving)
2. `isLoading`: The second entry is true if it's still requesting the flag from the server and false if it's finished loading (useful for displaying loading indicators for example) +### `Laika` component + +```tsx +interface LaikaProps { + feature: string + env?: string + uri?: string + cacheTimeout?: number, + onTrue: React.ReactElement | false + onFalse: React.ReactElement | false +} +``` + +Works analog to the `useLaika` hook, except that it's a component. +It will not render any children while the request is still loading the feature flag from Laika. + ### `getFeatureStatus` utility function Retrieves the feature flag from the API and returns a promise that can be `await`ed. diff --git a/package.json b/package.json index bd2cfb2..7d70ea1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "laika-react", - "version": "1.0.0", + "version": "1.1.0", "description": "React Laika client", "homepage": "https://github.com/MEDIGO", "keywords": [ diff --git a/src/component.test.tsx b/src/component.test.tsx new file mode 100644 index 0000000..85039a4 --- /dev/null +++ b/src/component.test.tsx @@ -0,0 +1,60 @@ +import { mount } from '@cypress/react' +import { Laika } from 'lib/component' +import { Config, LaikaContext } from 'lib/config' +import { mockRequest } from 'lib/mock/mockRequest' +import { cy, describe, it } from 'local-cypress' +import React from 'react' + +describe('component', () => { + const uri = 'https://laika.example.com' + + it('with-parameters', () => { + mockRequest('component-test', uri, 'test', true) + + mount( + Enabled} + onFalse={
Disabled
} + />, + ) + cy.get('div').contains('Enabled') + }) + + it('with-parameters-disabled', () => { + mockRequest('component-test', uri, 'test', false) + + mount( + Enabled} + onFalse={
Disabled
} + />, + ) + cy.get('div').contains('Disabled') + }) + + it('with-context', () => { + mockRequest('component-test', uri, 'test', true) + + const ctx: Config = { + env: 'test', + uri, + } + + mount( + + Enabled} + onFalse={
Disabled
} + /> +
, + ) + cy.get('div').contains('Enabled') + }) +}) diff --git a/src/component.tsx b/src/component.tsx new file mode 100644 index 0000000..bd381ff --- /dev/null +++ b/src/component.tsx @@ -0,0 +1,34 @@ +import { bool, node, number, oneOfType, string } from 'prop-types' +import React from 'react' +import { useLaika } from 'lib/hook' + +export interface LaikaProps { + feature: string + env?: string + uri?: string + cacheTimeout?: number + onTrue: React.ReactElement | false + onFalse: React.ReactElement | false +} + +export function Laika(props: LaikaProps) { + const [featureEnabled, featureIsLoading] = useLaika( + props.feature, + props.uri, + props.env, + props.cacheTimeout, + ) + + const children = featureEnabled ? props.onTrue : props.onFalse + return <>{!featureIsLoading && children} +} + +// For using it with JavaScript +Laika.propTypes = { + feature: string.isRequired, + uri: string, + env: string, + cacheTimeout: number, + onTrue: oneOfType([node, bool]).isRequired, + onFalse: oneOfType([node, bool]).isRequired, +} diff --git a/src/hook.test.tsx b/src/hook.test.tsx index 68dde35..b5099fd 100644 --- a/src/hook.test.tsx +++ b/src/hook.test.tsx @@ -1,14 +1,14 @@ import { mount } from '@cypress/react' +import { Config, LaikaContext } from 'lib/config' +import { useLaika } from 'lib/hook' +import { mockRequest } from 'lib/mock/mockRequest' import { cy, describe, it } from 'local-cypress' import React from 'react' -import { useLaika } from './hook' -import { mockRequest } from './mock/mockRequest' -import { Config, LaikaContext } from './config' describe('useLaika', () => { const uri = 'https://laika.example.com' - it('with parameters', () => { + it('with-parameters', () => { mockRequest('useLaika-test', uri, 'test', true) function TestComp() { @@ -21,7 +21,20 @@ describe('useLaika', () => { cy.get('div').contains('Enabled') }) - it('with context', () => { + it('with-parameters-disabled', () => { + mockRequest('useLaika-test', uri, 'test', false) + + function TestComp() { + const [flag] = useLaika('useLaika-test', uri, 'test') + + return
{flag ? 'Enabled' : 'Disabled'}
+ } + + mount() + cy.get('div').contains('Disabled') + }) + + it('with-context', () => { mockRequest('useLaika-test', uri, 'test', true) function TestComp() { diff --git a/src/index.ts b/src/index.ts index 1e2b92b..c17b60a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,3 +1,4 @@ -export { getFeatureStatus } from './utils' -export { useLaika } from './hook' -export { Config, LaikaContext } from './config' +export { getFeatureStatus } from 'lib/utils' +export { useLaika } from 'lib/hook' +export { Config, LaikaContext } from 'lib/config' +export { Laika } from 'lib/component' diff --git a/src/mock/mockRequest.ts b/src/mock/mockRequest.ts index 02a7e87..7d233bf 100644 --- a/src/mock/mockRequest.ts +++ b/src/mock/mockRequest.ts @@ -12,5 +12,6 @@ export function mockRequest( headers: { 'content-type': 'application/json', }, + delay: 500, }) } diff --git a/src/utils.test.ts b/src/utils.test.ts index 1e7a767..3a8f154 100644 --- a/src/utils.test.ts +++ b/src/utils.test.ts @@ -1,22 +1,22 @@ import { cy, describe, it } from 'local-cypress' -import { mockRequest } from './mock/mockRequest' -import { getFeatureStatus } from './utils' +import { mockRequest } from 'lib/mock/mockRequest' +import { getFeatureStatus } from 'lib/utils' describe('Utilities', () => { describe('getFeatureStatus', () => { - it('acts on false', () => { + it('acts-on-false', () => { mockRequest('cache-test', '', 'test', false) .then(() => getFeatureStatus('cache-test', '', 'test')) .should('eq', false) }) - it('acts on true', () => { + it('acts-on-true', () => { mockRequest('cache-test', '', 'test', true) .then(() => getFeatureStatus('cache-test', '', 'test')) .should('eq', true) }) - it('caches the flag', () => { + it('caches-the-flag', () => { cy.clock() mockRequest('cache-test', '', 'test', true) .then(() => getFeatureStatus('cache-test', '', 'test'))