Skip to content

[BUG] setForcedDecision does not work after update to version 3.0.1 #256

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
1 task done
haivle opened this issue Apr 5, 2024 · 14 comments
Closed
1 task done

[BUG] setForcedDecision does not work after update to version 3.0.1 #256

haivle opened this issue Apr 5, 2024 · 14 comments
Labels
acknowledged bug Something isn't working

Comments

@haivle
Copy link

haivle commented Apr 5, 2024

Is there an existing issue for this?

  • I have searched the existing issues

SDK Version

@optimizely/react-sdk: 3.0.1

Current Behavior

After calling setForcedDecision, useDecision(name, { autoUpdate: true }) is updated.

Expected Behavior

useDecision returns the latest data

Steps To Reproduce

  1. Initialise Optimizely instance
optimizelyInstance = createInstance({
        sdkKey: env.OPTIMIZELY_SDK_KEY,
        odpOptions: {
               disabled: true,
        },
        logLevel: env.IS_VERBOSE ? 1 : 4,
});

optimizelyInstance.onUserUpdate((a) => {
      optimizely.setForcedDecision({ flagKey: "flag1" }, { variationKey: "variation1" });
});
  1. In React
const [decision] = useDecision("flag1", { 
    autoUpdate: true 
}); 

React Framework

No response

Browsers impacted

No response

Link

No response

Logs

No response

Severity

Blocking development

Workaround/Solution

No response

Recent Change

No response

Conflicts

No response

@haivle haivle added bug Something isn't working needs-triage labels Apr 5, 2024
@mikechu-optimizely
Copy link
Contributor

Let me loop back to this. I'm working to finalise #255

@mikechu-optimizely
Copy link
Contributor

We've released v3.1.0 of the React SDK.

When you have a moment, please let me know if setForcedDecision works as you/we expect.

I'll create a test scenario as you've described to test.

@byron-ino
Copy link

Hey there! Was going to write up an issue about this same topic. Currently on v3.1.0 and was running into issues forcing a user into a variation and wasn't sure if this is related to the same bug or not, but thought I would post it here.

We are currently writing a light wrapper around the useDecision react hook so that we do things like pass overrides and also have logic to force decisions before calling the useDecision hook.

Here is a simplified version of what our wrapper looks like:

function useDecisionWrapper(featureKey, options, overrides){ 
  const { optimizely } = useContext(OptimizelyContext);

  const [decisionContext, forcedDecision] = getForcedDecisionOverrides(featureKey); // grabs data from cookies to force a decision
  if(decisionContext && forcedDecision){
      const user = optimizely.getUserContext();
      user?.setForcedDecision(decisionContext, forcedDecision);
  }

  return useDecision(featureKey, options, overrides);
}

I'd assume that since we called setForcedDecision for the current user, calling useDecision would respect the forced decision but it seems to be not. Would love some feedback or suggestions if I am doing something wrong! I will also test v3.1.0 tomorrow! Thank you :)

@mikechu-optimizely
Copy link
Contributor

I did a quick code dive and see that in the JS SDK, decide() finds and should use a matched forced decision.

I've created an internal ticket (FSSDK-10120) to trace.

@byron-ino
Copy link

Hey there @mikechu-optimizely! Just wanted to follow up on some findings I did today.

While playing around with the APIs, one interesting thing I found was that calling .decide() from the userContext object seems to force users into a decision as expected, but calling .decide() from the optimizely instance does not.

Example below shows us calling both user.decide() and optimizely.decide() and seeing different results

 optimizely = createOptimizelyInstance({
    sdkKey,
    datafile,
    datafileOptions: {
      autoUpdate: isServerSide ? false : true,
      ...datafileOptions,
    },
    logLevel: 'DEBUG',
    eventDispatcher: IS_PROD || enableTracking ? eventDispatcher : logOnlyEventDispatcher, // always enable tracking in prod
    odpOptions: { disabled: true }, // only needed if advanced audience targeting is on
    ...config,
  });

    const user = optimizely.getUserContext();
    user.setForcedDecision({ flagKey: "migration_initial_flag", ruleKey: 'initial_experiment' }, { variationKey: "off" });
    optimizely.setForcedDecision({ flagKey: "migration_initial_flag", ruleKey: 'initial_experiment' }, { variationKey: "off" });

    const optimizelyDecision = optimizely.decide('migration_initial_flag');
    const userDecision = user.decide('migration_initial_flag');

    console.log('optimizelyDecision', optimizelyDecision);
    console.log('userDecision:', userDecision);

The results of the console log are as followed:

optimizelyDecision:
{
    "variationKey": "on",
    "enabled": true,
    "variables": {},
    "ruleKey": "initial_experiment",
    "flagKey": "migration_initial_flag",
    "userContext": {
        "id": "e9b20618-732d-478e-9a9e-237496274489",
        "attributes": {
            "grx_internal_user": false,
            "location": "",
            "$opt_user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36",
            "environment": "dev",
            "url_path": "/feature"
        }
    },
    "reasons": []
}
userDecision

{
  "variationKey": "off",
  "enabled": false,
  "variables": {},
  "ruleKey": "initial_experiment",
  "flagKey": "migration_initial_flag",
  "userContext": {
      "_qualifiedSegments": null,
      "optimizely": {}, //removed because its too big
      "userId": "e9b20618-732d-478e-9a9e-237496274489",
      "attributes": {
          "grx_internal_user": false,
          "location": "",
          "$opt_user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36",
          "environment": "dev",
          "url_path": "/feature"
      },
      "forcedDecisionsMap": {
          "migration_initial_flag": {
              "initial_experiment": {
                  "variationKey": "off"
              }
          }
      }
  },
  "reasons": [
      "Variation (off) is mapped to flag (migration_initial_flag), rule (initial_experiment) and user (e9b20618-732d-478e-9a9e-237496274489) in the forced decision map."
  ]
}

As we can see, calling user.decide() respects the call to setForcedDecision but optimizely.decide() does not respect the setForcedDecision call. This is important because the underlying implementation of the useDecision react hook uses optimizely.decide() (Reference in Hooks.ts)

Any guidance or insight to successfully getting the useDecision hook to respect forced decisions would definitely be appreciated 🙏🏽

@mikechu-optimizely
Copy link
Contributor

Thanks for code diving with me.

I see in the underlying JS SDK that the OptimizelyUserContext.decide snags a copy of the current userContext with the forced decisions (if present) on its way into the client's decide() method.

So yeah, that's our difference.

🤔: React SDK's use of the client decide() instead of the user context's method means that forced decisions are not returned by the useDecision hook. I think this may have been by design at some point. I need to talk with our architect on this point since it's a public facing design.

@iamstarkov
Copy link

forced decisions is very important for automated tests and other quality assurance processes to make sure feature is working in production manually before starting gradual rollout. its been more than 5 months since issue was filed and last communication on the matter.

Its frustrating and disappointing as a paying corporate customer to see important feature being broken for months without end in sight

@mikechu-optimizely do you mind to prioritise the fix for this once working feature?

@mikechu-optimizely
Copy link
Contributor

I've pulled this Issue into today's stand-up. I'll update here by COB.

cc @junaed-optimizely

@mikechu-optimizely
Copy link
Contributor

We've pulled this issue & work ticket into this sprint.

@junaed-optimizely
Copy link
Contributor

A new release v3.2.1 is out with the fix.

@iamstarkov, @byron-ino let us know if an upgrade fix the issue for you.

Thanks for your patience.

@juanpicado
Copy link

I was also following this bug ^.^, I just tested my local project with the new version and works as expected 👍🏼 I hope others have the same outcome. Thanks for the quick fix.

@iamstarkov
Copy link

@junaed-optimizely @mikechu-optimizely thank you for a quick fix, we can confirm it works now

@mikechu-optimizely
Copy link
Contributor

mikechu-optimizely commented Aug 16, 2024

Thanks for the confirmation updates. 🙏

@junaed-optimizely
Copy link
Contributor

The issue has been resolved and confirmed by the clients. Closing this issue now. Thanks everyone!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
acknowledged bug Something isn't working
Projects
None yet
Development

No branches or pull requests

6 participants