Skip to content

Commit

Permalink
fixup: mix-in-noop
Browse files Browse the repository at this point in the history
Signed-off-by: Todd Baert <[email protected]>
  • Loading branch information
toddbaert committed Jul 29, 2024
1 parent 806d046 commit c2f789b
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 16 deletions.
21 changes: 19 additions & 2 deletions packages/react/src/provider/test-provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,16 @@ type TestProviderProps = Omit<React.ComponentProps<typeof OpenFeatureProvider>,
| {
/**
* An optional partial provider to pass for full control over the flag resolution for this OpenFeatureTestProvider context.
* Any un-implemented methods or properties will no-op.
*/
provider?: Partial<Provider>;
flagValueMap?: never;
delayMs?: never;
}
);

const TEST_VARIANT = 'test-variant';
const TEST_VARIANT = 'test-variant';
const TEST_PROVIDER = 'test-provider';

// internal provider which is basically the in-memory provider with a simpler config and some optional fake delays
class TestProvider extends InMemoryProvider {
Expand Down Expand Up @@ -79,7 +81,7 @@ class TestProvider extends InMemoryProvider {
export function OpenFeatureTestProvider(testProviderOptions: TestProviderProps) {
const { flagValueMap, provider } = testProviderOptions;
const effectiveProvider = (
flagValueMap ? new TestProvider(flagValueMap, testProviderOptions.delayMs) : provider || NOOP_PROVIDER
flagValueMap ? new TestProvider(flagValueMap, testProviderOptions.delayMs) : mixInNoop(provider) || NOOP_PROVIDER
) as Provider;
testProviderOptions.domain
? OpenFeature.setProvider(testProviderOptions.domain, effectiveProvider)
Expand All @@ -91,3 +93,18 @@ export function OpenFeatureTestProvider(testProviderOptions: TestProviderProps)
</OpenFeatureProvider>
);
}

// mix in the no-op provider when the partial is passed
function mixInNoop(provider: Partial<Provider> = {}) {
// fill in any missing methods with no-ops
for (const prop of Object.getOwnPropertyNames(Object.getPrototypeOf(NOOP_PROVIDER)).filter(prop => prop !== 'constructor')) {
if (!Object.getPrototypeOf(provider)[prop]) {
(provider as {[key: string]: keyof Provider})[prop] = Object.getPrototypeOf(NOOP_PROVIDER)[prop];
}
}
// fill in the metadata if missing
if (!provider.metadata || !provider.metadata.name) {
(provider.metadata as unknown) = { name: TEST_PROVIDER };
}
return provider;
}
45 changes: 31 additions & 14 deletions packages/react/test/test-provider.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@ import { OpenFeatureTestProvider, useFlag } from '../src';
const FLAG_KEY = 'thumbs';

function TestComponent() {
const { value: thumbs } = useFlag(FLAG_KEY, false);
const { value: thumbs, reason } = useFlag(FLAG_KEY, false);
return (
<>
<div>{thumbs ? 'πŸ‘' : 'πŸ‘Ž'}</div>
</>
<div>reason: {`${reason}`}</div>
</>
);
}

Expand Down Expand Up @@ -56,27 +57,43 @@ describe('OpenFeatureTestProvider', () => {
});

describe('provider set', () => {
class MyTestProvider implements Partial<Provider> {
metadata = {
name: 'my test provider',
};
resolveBooleanEvaluation(): ResolutionDetails<boolean> {
return {
value: true,
variant: 'test-variant',
reason: 'MY_REASON',
};
}
}
const reason = 'MY_REASON';

it('renders provider-returned value', async () => {

class MyTestProvider implements Partial<Provider> {
resolveBooleanEvaluation(): ResolutionDetails<boolean> {
return {
value: true,
variant: 'test-variant',
reason,
};
}
}

render(
<OpenFeatureTestProvider provider={new MyTestProvider()}>
<TestComponent />
</OpenFeatureTestProvider>,
);

expect(await screen.findByText('πŸ‘')).toBeInTheDocument();
expect(await screen.findByText(/reason/)).toBeInTheDocument();
});

it('falls back to no-op for missing methods', async () => {

class MyEmptyProvider implements Partial<Provider> {
}

render(
<OpenFeatureTestProvider provider={new MyEmptyProvider()}>
<TestComponent />
</OpenFeatureTestProvider>,
);

expect(await screen.findByText('πŸ‘Ž')).toBeInTheDocument();
expect(await screen.findByText(/No-op/)).toBeInTheDocument();
});
});
});

0 comments on commit c2f789b

Please sign in to comment.