diff --git a/libraryValidations/JavaScript/featureEvaluationValidation.test.ts b/libraryValidations/JavaScript/featureEvaluationValidation.test.ts index f9ac7b5..7db2867 100644 --- a/libraryValidations/JavaScript/featureEvaluationValidation.test.ts +++ b/libraryValidations/JavaScript/featureEvaluationValidation.test.ts @@ -3,7 +3,7 @@ import * as fs from "node:fs/promises"; import { FeatureManager, ConfigurationObjectFeatureFlagProvider } from "@microsoft/feature-management"; -import {FILE_PATH, SAMPLE_JSON_KEY, TESTS_JSON_KEY, validateFeatureEvaluation, FeatureFlagTest } from "./utils.js"; +import { FILE_PATH, SAMPLE_JSON_KEY, TESTS_JSON_KEY, validateFeatureEvaluation, FeatureFlagTest } from "./utils.js"; async function runTest(testName: string) { const config = JSON.parse(await fs.readFile(FILE_PATH + testName + SAMPLE_JSON_KEY, "utf8")); @@ -11,7 +11,7 @@ async function runTest(testName: string) { const ffProvider = new ConfigurationObjectFeatureFlagProvider(config); const fm = new FeatureManager(ffProvider); - for (const testcase of testcases){ + for (const testcase of testcases) { validateFeatureEvaluation(testcase, fm); } } diff --git a/libraryValidations/JavaScript/package.json b/libraryValidations/JavaScript/package.json index 8824aab..e13bb1c 100644 --- a/libraryValidations/JavaScript/package.json +++ b/libraryValidations/JavaScript/package.json @@ -17,10 +17,10 @@ "sinon": "^15.2.0", "tslib": "^2.6.2", "typescript": "^5.3.3", - "@microsoft/feature-management": "2.0.0-preview.3", - "@microsoft/feature-management-applicationinsights-browser": "2.0.0-preview.3", - "@microsoft/feature-management-applicationinsights-node": "2.0.0-preview.3", - "@azure/app-configuration-provider": "2.0.0-preview.1", + "@microsoft/feature-management": "latest", + "@microsoft/feature-management-applicationinsights-browser": "latest", + "@microsoft/feature-management-applicationinsights-node": "latest", + "@azure/app-configuration-provider": "latest", "@microsoft/applicationinsights-web": "^3.3.4", "applicationinsights": "^2.9.6" } diff --git a/libraryValidations/JavaScript/telemetryValidation.test.ts b/libraryValidations/JavaScript/telemetryValidation.test.ts new file mode 100644 index 0000000..c5c1b5c --- /dev/null +++ b/libraryValidations/JavaScript/telemetryValidation.test.ts @@ -0,0 +1,69 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import * as sinon from "sinon"; +import * as fs from "node:fs/promises"; +import { FeatureManager, ConfigurationObjectFeatureFlagProvider } from "@microsoft/feature-management"; +import { createTelemetryPublisher as createNodeTelemetryPublisher } from "@microsoft/feature-management-applicationinsights-node"; +import { createTelemetryPublisher as createBrowserTelemetryPublisher } from "@microsoft/feature-management-applicationinsights-browser"; +import { FILE_PATH, SAMPLE_JSON_KEY, TESTS_JSON_KEY, validateFeatureEvaluation, validateTelemetry, FeatureFlagTest } from "./utils.js"; +import { ApplicationInsights } from "@microsoft/applicationinsights-web"; +import applicationInsights from "applicationinsights"; + +// For telemetry validation +let eventNameToValidate; +let eventPropertiesToValidate; + +applicationInsights.setup("DUMMY-CONNECTION-STRING").start(); +sinon.stub(applicationInsights.defaultClient, "trackEvent").callsFake((event) => { + eventNameToValidate = event.name; + eventPropertiesToValidate = event.properties; +}); + +const appInsights = new ApplicationInsights({ config: { connectionString: "DUMMY-CONNECTION-STRING" }}); +sinon.stub(appInsights, "trackEvent").callsFake((event, customProperties) => { + eventNameToValidate = event.name; + eventPropertiesToValidate = customProperties; +}); + +async function runTestWithNodePackage(testName: string) { + const config = JSON.parse(await fs.readFile(FILE_PATH + testName + SAMPLE_JSON_KEY, "utf8")); + const testcases: FeatureFlagTest[] = JSON.parse(await fs.readFile(FILE_PATH + testName + TESTS_JSON_KEY, "utf8")); + const ffProvider = new ConfigurationObjectFeatureFlagProvider(config); + const fm = new FeatureManager(ffProvider, { onFeatureEvaluated: createNodeTelemetryPublisher(applicationInsights.defaultClient) }); + + for (const testcase of testcases) { + const featureFlagName = testcase.FeatureFlagName; + const context = { userId: testcase.Inputs?.User, groups: testcase.Inputs?.Groups }; + await fm.getVariant(featureFlagName, context); + validateTelemetry(testcase, undefined, eventNameToValidate, eventPropertiesToValidate); + validateFeatureEvaluation(testcase, fm); + } +} + +async function runTestWithBrowserPackage(testName: string) { + const config = JSON.parse(await fs.readFile(FILE_PATH + testName + SAMPLE_JSON_KEY, "utf8")); + const testcases: FeatureFlagTest[] = JSON.parse(await fs.readFile(FILE_PATH + testName + TESTS_JSON_KEY, "utf8")); + const ffProvider = new ConfigurationObjectFeatureFlagProvider(config); + const fm = new FeatureManager(ffProvider, { onFeatureEvaluated: createBrowserTelemetryPublisher(appInsights) }); + + for (const testcase of testcases) { + const featureFlagName = testcase.FeatureFlagName; + const context = { userId: testcase.Inputs?.User, groups: testcase.Inputs?.Groups }; + await fm.getVariant(featureFlagName, context); + validateTelemetry(testcase, undefined, eventNameToValidate, eventPropertiesToValidate); + validateFeatureEvaluation(testcase, fm); + } +} + +describe("telemetry with provider and node package", function () { + it("should pass BasicTelemetry test", async () => { + await runTestWithNodePackage("BasicTelemetry"); + }); +}); + +describe("telemetry with provider and browser package", function () { + it("should pass BasicTelemetry test", async () => { + await runTestWithBrowserPackage("BasicTelemetry"); + }); +}); diff --git a/libraryValidations/JavaScript/telemetryWithProviderValidation.test.ts b/libraryValidations/JavaScript/telemetryWithProviderValidation.test.ts index edd37af..a9177df 100644 --- a/libraryValidations/JavaScript/telemetryWithProviderValidation.test.ts +++ b/libraryValidations/JavaScript/telemetryWithProviderValidation.test.ts @@ -7,7 +7,7 @@ import { load } from "@azure/app-configuration-provider"; import { FeatureManager, ConfigurationMapFeatureFlagProvider } from "@microsoft/feature-management"; import { createTelemetryPublisher as createNodeTelemetryPublisher } from "@microsoft/feature-management-applicationinsights-node"; import { createTelemetryPublisher as createBrowserTelemetryPublisher } from "@microsoft/feature-management-applicationinsights-browser"; -import {FILE_PATH, TESTS_JSON_KEY, FeatureFlagTest, validateFeatureEvaluation, validateTelemetryWithProvider } from "./utils.js"; +import { FILE_PATH, TESTS_JSON_KEY, FeatureFlagTest, validateFeatureEvaluation, validateTelemetry } from "./utils.js"; import { ApplicationInsights } from "@microsoft/applicationinsights-web"; import applicationInsights from "applicationinsights"; @@ -48,11 +48,12 @@ async function runTestWithProviderAndNodePackage(testName: string) { const testcases: FeatureFlagTest[] = JSON.parse(await fs.readFile(FILE_PATH + testName + TESTS_JSON_KEY, "utf8")); const ffProvider = new ConfigurationMapFeatureFlagProvider(config); const fm = new FeatureManager(ffProvider, { onFeatureEvaluated: createNodeTelemetryPublisher(applicationInsights.defaultClient) }); - for (const testcase of testcases){ + for (const testcase of testcases) { const featureFlagName = testcase.FeatureFlagName; const context = { userId: testcase.Inputs?.User, groups: testcase.Inputs?.Groups }; await fm.getVariant(featureFlagName, context); - validateTelemetryWithProvider(testcase, connectionString, eventNameToValidate, eventPropertiesToValidate); + validateTelemetry(testcase, connectionString, eventNameToValidate, eventPropertiesToValidate); + validateFeatureEvaluation(testcase, fm); } } @@ -77,11 +78,12 @@ async function runTestWithProviderAndBrowserPackage(testName: string) { const testcases: FeatureFlagTest[] = JSON.parse(await fs.readFile(FILE_PATH + testName + TESTS_JSON_KEY, "utf8")); const ffProvider = new ConfigurationMapFeatureFlagProvider(config); const fm = new FeatureManager(ffProvider, { onFeatureEvaluated: createBrowserTelemetryPublisher(appInsights) }); - for (const testcase of testcases){ + for (const testcase of testcases) { const featureFlagName = testcase.FeatureFlagName; const context = { userId: testcase.Inputs?.User, groups: testcase.Inputs?.Groups }; await fm.getVariant(featureFlagName, context); - validateTelemetryWithProvider(testcase, connectionString, eventNameToValidate, eventPropertiesToValidate); + validateTelemetry(testcase, connectionString, eventNameToValidate, eventPropertiesToValidate); + validateFeatureEvaluation(testcase, fm); } } diff --git a/libraryValidations/JavaScript/utils.ts b/libraryValidations/JavaScript/utils.ts index 05633c8..43dccc6 100644 --- a/libraryValidations/JavaScript/utils.ts +++ b/libraryValidations/JavaScript/utils.ts @@ -108,10 +108,10 @@ export async function validateFeatureEvaluation(testcase: FeatureFlagTest, featu } } -export function validateTelemetryWithProvider(testcase: FeatureFlagTest, connectionString: string, eventNameToValidate: string, eventPropertiesToValidate: any) { - // if (testcase.Telemetry?.EventName) { - // expect(eventNameToValidate).to.eq(testcase.Telemetry.EventName); - // } +export function validateTelemetry(testcase: FeatureFlagTest, connectionString: string | undefined, eventNameToValidate: string, eventPropertiesToValidate: any) { + if (testcase.Telemetry?.EventName) { + expect(eventNameToValidate).to.eq(testcase.Telemetry.EventName); + } const eventProperties = testcase.Telemetry?.EventProperties; if (eventProperties) { @@ -143,16 +143,21 @@ export function validateTelemetryWithProvider(testcase: FeatureFlagTest, connect expect(eventPropertiesToValidate["FeatureFlagId"]).to.eq(eventProperties.FeatureFlagId); } if (eventProperties.FeatureFlagReference) { - const endpointMatch = connectionString.match(/Endpoint=([^;]+)/); - if (endpointMatch) { - expect(eventPropertiesToValidate["FeatureFlagReference"]).to.eq(endpointMatch[1] + eventProperties.FeatureFlagReference); + if (connectionString === undefined) { + expect(eventPropertiesToValidate["FeatureFlagReference"]).to.eq(eventProperties.FeatureFlagReference); } else { - expect.fail("Connection string does not contain endpoint."); + const endpointMatch = connectionString.match(/Endpoint=([^;]+)/); + if (endpointMatch) { + expect(eventPropertiesToValidate["FeatureFlagReference"]).to.eq(endpointMatch[1] + eventProperties.FeatureFlagReference); + } + else { + expect.fail("Connection string does not contain endpoint."); + } } } if (eventProperties.TargetingId) { expect(eventPropertiesToValidate["TargetingId"]).to.eq(eventProperties.TargetingId); } } -} \ No newline at end of file +}