diff --git a/.github/workflows/pr-checks.yaml b/.github/workflows/pr-checks.yaml index 69d53fa9a..f5290655a 100644 --- a/.github/workflows/pr-checks.yaml +++ b/.github/workflows/pr-checks.yaml @@ -65,12 +65,6 @@ jobs: e2e: runs-on: ubuntu-latest - services: - flagd: - image: ghcr.io/open-feature/flagd-testbed:latest - ports: - - 8013:8013 - steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1d7335586..0fb4e5159 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -30,11 +30,7 @@ Run tests with `npm test`. ### End-to-End Tests -The continuous integration runs a set of [gherkin e2e tests](https://github.com/open-feature/test-harness/blob/main/features/evaluation.feature) using [`flagd`](https://github.com/open-feature/flagd). These tests run with the "e2e" npm script. If you'd like to run them locally, you can start the flagd testbed with -``` -docker run -p 8013:8013 ghcr.io/open-feature/flagd-testbed:latest -``` -and then run +The continuous integration runs a set of [gherkin e2e tests](https://github.com/open-feature/test-harness/blob/main/features/evaluation.feature) using in-memory provider. These tests run with the "e2e" npm script. If you'd like to run them locally, follow the steps below: ``` npm run e2e-server ``` diff --git a/jest.config.ts b/jest.config.ts index eeacc3aa8..0d1d2e2a6 100644 --- a/jest.config.ts +++ b/jest.config.ts @@ -138,7 +138,6 @@ export default { preset: 'ts-jest', testMatch: ['/packages/server/e2e/**/*.spec.ts'], modulePathIgnorePatterns: ['.*/node-modules/'], - setupFiles: ['/packages/server/e2e/step-definitions/setup.ts'], moduleNameMapper: { '@openfeature/core': '/packages/shared/src', }, @@ -149,7 +148,6 @@ export default { preset: 'ts-jest', testMatch: ['/packages/client/e2e/**/*.spec.ts'], modulePathIgnorePatterns: ['.*/node-modules/'], - setupFiles: ['/packages/client/e2e/step-definitions/setup.ts'], moduleNameMapper: { '^uuid$': require.resolve('uuid'), '^(.*)\\.js$': ['$1', '$1.js'], diff --git a/packages/client/e2e/step-definitions/evaluation.spec.ts b/packages/client/e2e/step-definitions/evaluation.spec.ts index 017661b71..f03e76801 100644 --- a/packages/client/e2e/step-definitions/evaluation.spec.ts +++ b/packages/client/e2e/step-definitions/evaluation.spec.ts @@ -7,7 +7,8 @@ import { ResolutionDetails, StandardResolutionReasons, } from '@openfeature/core'; -import { OpenFeature, ProviderEvents } from '../..'; +import { OpenFeature, ProviderEvents, InMemoryProvider } from '../../src'; +import flagConfiguration from './flags-config'; // load the feature file. const feature = loadFeature('packages/client/e2e/features/evaluation.feature'); @@ -17,6 +18,7 @@ const client = OpenFeature.getClient(); const givenAnOpenfeatureClientIsRegisteredWithCacheDisabled = ( given: (stepMatcher: string, stepDefinitionCallback: () => void) => void ) => { + OpenFeature.setProvider(new InMemoryProvider(flagConfiguration)); given('a provider is registered with cache disabled', () => undefined); }; @@ -70,10 +72,11 @@ defineFeature(feature, (test) => { givenAnOpenfeatureClientIsRegisteredWithCacheDisabled(given); + when( /^an integer flag with key "(.*)" is evaluated with default value (\d+)$/, - (key: string, defaultValue: number) => { - value = client.getNumberValue(key, defaultValue); + (key: string, defaultValue: string) => { + value = client.getNumberValue(key, Number.parseInt(defaultValue)); } ); diff --git a/packages/client/e2e/step-definitions/flags-config.ts b/packages/client/e2e/step-definitions/flags-config.ts new file mode 100644 index 000000000..17956b13f --- /dev/null +++ b/packages/client/e2e/step-definitions/flags-config.ts @@ -0,0 +1,71 @@ +export default { + 'boolean-flag': { + disabled: false, + variants: { + on: true, + off: false, + }, + defaultVariant: 'on', + }, + 'string-flag': { + disabled: false, + variants: { + greeting: 'hi', + parting: 'bye', + }, + defaultVariant: 'greeting', + }, + 'integer-flag': { + disabled: false, + variants: { + one: 1, + ten: 10, + }, + defaultVariant: 'ten', + }, + 'float-flag': { + disabled: false, + variants: { + tenth: 0.1, + half: 0.5, + }, + defaultVariant: 'half', + }, + 'object-flag': { + disabled: false, + variants: { + empty: {}, + template: { + showImages: true, + title: 'Check out these pics!', + imagesPerPage: 100, + }, + }, + defaultVariant: 'template', + }, + 'context-aware': { + disabled: false, + variants: { + internal: 'INTERNAL', + external: 'EXTERNAL', + }, + defaultVariant: 'external', + // eslint-disable-next-line @typescript-eslint/no-explicit-any + contextEvaluator(ctx: any) { + const { fn, ln, age, customer } = ctx; + if (fn === 'Sulisław' && ln === 'Świętopełk' && age === 29 && customer === false) { + return 'internal'; + } else { + return 'external'; + } + }, + }, + 'wrong-flag': { + disabled: false, + variants: { + one: 'uno', + two: 'dos', + }, + defaultVariant: 'one', + }, +}; diff --git a/packages/client/e2e/step-definitions/setup.ts b/packages/client/e2e/step-definitions/setup.ts deleted file mode 100644 index 5f2256731..000000000 --- a/packages/client/e2e/step-definitions/setup.ts +++ /dev/null @@ -1,19 +0,0 @@ -import assert from 'assert'; -import { OpenFeature } from '../..'; -import { FlagdWebProvider } from '@openfeature/flagd-web-provider'; - -const FLAGD_WEB_NAME = 'flagd-web'; - -// register the flagd provider before the tests. -console.log('Setting flagd web provider...'); -OpenFeature.setProvider(new FlagdWebProvider({ - host: 'localhost', - port: 8013, - tls: false, - maxRetries: -1, -})); -assert( - OpenFeature.providerMetadata.name === FLAGD_WEB_NAME, - new Error(`Expected ${FLAGD_WEB_NAME} provider to be configured, instead got: ${OpenFeature.providerMetadata.name}`) -); -console.log('flagd web provider configured!'); diff --git a/packages/server/e2e/step-definitions/evaluation.spec.ts b/packages/server/e2e/step-definitions/evaluation.spec.ts index 1794ffdb0..957bd8fa9 100644 --- a/packages/server/e2e/step-definitions/evaluation.spec.ts +++ b/packages/server/e2e/step-definitions/evaluation.spec.ts @@ -8,7 +8,8 @@ import { StandardResolutionReasons, ProviderEvents, } from '@openfeature/core'; -import { OpenFeature } from '../..'; +import { OpenFeature, InMemoryProvider } from '../../src'; +import flagConfiguration from './flags-config'; // load the feature file. const feature = loadFeature('packages/server/e2e/features/evaluation.feature'); @@ -18,7 +19,9 @@ const client = OpenFeature.getClient(); const givenAnOpenfeatureClientIsRegisteredWithCacheDisabled = ( given: (stepMatcher: string, stepDefinitionCallback: () => void) => void ) => { - // TODO: when the FlagdProvider is updated to support caching, we may need to disable it here for this test to work as expected. + OpenFeature.setProvider( + new InMemoryProvider(flagConfiguration), + ); given('a provider is registered with cache disabled', () => undefined); }; diff --git a/packages/server/e2e/step-definitions/flags-config.ts b/packages/server/e2e/step-definitions/flags-config.ts new file mode 100644 index 000000000..17956b13f --- /dev/null +++ b/packages/server/e2e/step-definitions/flags-config.ts @@ -0,0 +1,71 @@ +export default { + 'boolean-flag': { + disabled: false, + variants: { + on: true, + off: false, + }, + defaultVariant: 'on', + }, + 'string-flag': { + disabled: false, + variants: { + greeting: 'hi', + parting: 'bye', + }, + defaultVariant: 'greeting', + }, + 'integer-flag': { + disabled: false, + variants: { + one: 1, + ten: 10, + }, + defaultVariant: 'ten', + }, + 'float-flag': { + disabled: false, + variants: { + tenth: 0.1, + half: 0.5, + }, + defaultVariant: 'half', + }, + 'object-flag': { + disabled: false, + variants: { + empty: {}, + template: { + showImages: true, + title: 'Check out these pics!', + imagesPerPage: 100, + }, + }, + defaultVariant: 'template', + }, + 'context-aware': { + disabled: false, + variants: { + internal: 'INTERNAL', + external: 'EXTERNAL', + }, + defaultVariant: 'external', + // eslint-disable-next-line @typescript-eslint/no-explicit-any + contextEvaluator(ctx: any) { + const { fn, ln, age, customer } = ctx; + if (fn === 'Sulisław' && ln === 'Świętopełk' && age === 29 && customer === false) { + return 'internal'; + } else { + return 'external'; + } + }, + }, + 'wrong-flag': { + disabled: false, + variants: { + one: 'uno', + two: 'dos', + }, + defaultVariant: 'one', + }, +}; diff --git a/packages/server/e2e/step-definitions/jest.config.ts b/packages/server/e2e/step-definitions/jest.config.ts deleted file mode 100644 index c56a4ed00..000000000 --- a/packages/server/e2e/step-definitions/jest.config.ts +++ /dev/null @@ -1,16 +0,0 @@ -export default { - clearMocks: true, - collectCoverage: true, - coverageDirectory: 'coverage', - coverageProvider: 'v8', - globals: { - 'ts-jest': { - tsConfig: 'e2e/step-definitions/tsconfig.json', - }, - }, - moduleNameMapper: { - '^(.*)\\.js$': ['$1', '$1.js'], - }, - setupFiles: ['./setup.ts'], - preset: 'ts-jest', -}; diff --git a/packages/server/e2e/step-definitions/setup.ts b/packages/server/e2e/step-definitions/setup.ts deleted file mode 100644 index 850b598e9..000000000 --- a/packages/server/e2e/step-definitions/setup.ts +++ /dev/null @@ -1,14 +0,0 @@ -import assert from 'assert'; -import { OpenFeature } from '../..'; -import { FlagdProvider } from '@openfeature/flagd-provider'; - -const FLAGD_NAME = 'flagd Provider'; - -// register the flagd provider before the tests. -console.log('Setting flagd provider...'); -OpenFeature.setProvider(new FlagdProvider({ cache: 'disabled' })); -assert( - OpenFeature.providerMetadata.name === FLAGD_NAME, - new Error(`Expected ${FLAGD_NAME} provider to be configured, instead got: ${OpenFeature.providerMetadata.name}`) -); -console.log('flagd provider configured!');