Skip to content

Commit

Permalink
Remove duplicate FidesUpdated event and trigger FidesInitialized
Browse files Browse the repository at this point in the history
…twice instead (#4365)

Co-authored-by: Allison King <[email protected]>
  • Loading branch information
2 people authored and Kelsey-Ethyca committed Nov 1, 2023
1 parent 1be266e commit 561f828
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 110 deletions.
12 changes: 2 additions & 10 deletions clients/fides-js/src/fides-tcf.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,6 @@ import {
experienceIsValid,
FidesCookie,
hasSavedTcfPreferences,
isNewFidesCookie,
isPrivacyExperience,
tcfConsentCookieObjHasSomeConsentSet,
transformTcfPreferencesToCookieKeys,
Expand Down Expand Up @@ -213,7 +212,6 @@ const init = async (config: FidesConfig) => {
if (initialFides) {
Object.assign(_Fides, initialFides);
dispatchFidesEvent("FidesInitialized", cookie, config.options.debug);
dispatchFidesEvent("FidesUpdated", cookie, config.options.debug);
}
const experience = initialFides?.experience ?? config.experience;
const updatedFides = await initialize({
Expand All @@ -225,14 +223,8 @@ const init = async (config: FidesConfig) => {
});
Object.assign(_Fides, updatedFides);

// Dispatch the "FidesInitialized" event to update listeners with the initial
// state. Skip if we already initialized due to an existing cookie.
// For convenience, also dispatch the "FidesUpdated" event; this allows
// listeners to ignore the initialization event if they prefer
if (isNewFidesCookie(cookie)) {
dispatchFidesEvent("FidesInitialized", cookie, config.options.debug);
}
dispatchFidesEvent("FidesUpdated", cookie, config.options.debug);
// Dispatch the "FidesInitialized" event to update listeners with the initial state.
dispatchFidesEvent("FidesInitialized", cookie, config.options.debug);
};

// The global Fides object; this is bound to window.Fides if available
Expand Down
17 changes: 3 additions & 14 deletions clients/fides-js/src/fides.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,7 @@ import { gtm } from "./integrations/gtm";
import { meta } from "./integrations/meta";
import { shopify } from "./integrations/shopify";

import {
FidesCookie,
buildCookieConsentForExperiences,
isNewFidesCookie,
} from "./lib/cookie";
import { FidesCookie, buildCookieConsentForExperiences } from "./lib/cookie";
import {
FidesConfig,
FidesOptionOverrides,
Expand Down Expand Up @@ -114,7 +110,6 @@ const init = async (config: FidesConfig) => {
if (initialFides) {
Object.assign(_Fides, initialFides);
dispatchFidesEvent("FidesInitialized", cookie, config.options.debug);
dispatchFidesEvent("FidesUpdated", cookie, config.options.debug);
}
const experience = initialFides?.experience ?? config.experience;
const updatedFides = await initialize({
Expand All @@ -126,14 +121,8 @@ const init = async (config: FidesConfig) => {
});
Object.assign(_Fides, updatedFides);

// Dispatch the "FidesInitialized" event to update listeners with the initial
// state. Skip if we already initialized due to an existing cookie.
// For convenience, also dispatch the "FidesUpdated" event; this allows
// listeners to ignore the initialization event if they prefer
if (isNewFidesCookie(cookie)) {
dispatchFidesEvent("FidesInitialized", cookie, config.options.debug);
}
dispatchFidesEvent("FidesUpdated", cookie, config.options.debug);
// Dispatch the "FidesInitialized" event to update listeners with the initial state.
dispatchFidesEvent("FidesInitialized", cookie, config.options.debug);
};

// The global Fides object; this is bound to window.Fides if available
Expand Down
6 changes: 4 additions & 2 deletions clients/fides-js/src/lib/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { debugLog } from "./consent-utils";
/**
* Defines the available event names:
* - FidesInitialized: dispatched when initialization is complete, from Fides.init()
* - FidesUpdated: dispatched when preferences are updated, from updateConsentPreferences() or Fides.init()
* - FidesUpdated: dispatched when preferences are updated from updateConsentPreferences()
* - FidesUIShown: dispatched when either the banner or modal is shown to the user
* - FidesUIChanged: dispatched when preferences are changed but not saved, i.e. "dirty".
* - FidesModalClosed: dispatched when the modal is closed
Expand Down Expand Up @@ -45,11 +45,13 @@ export type FidesEvent = CustomEvent<FidesEventDetail>;
*
* Example usage:
* ```
* window.addEventListener("FidesInitialized", (evt) => console.log("Fides.consent initialized:", evt.detail.consent));
* window.addEventListener("FidesUpdated", (evt) => console.log("Fides.consent updated:", evt.detail.consent));
* ```
*
* The snippet above will print a console log whenever consent preferences are initialized/updated, like:
* The snippet above will print a console log whenever consent preferences are updated, like:
* ```
* Fides.consent initialized: { data_sales_and_sharing: false }
* Fides.consent updated: { data_sales_and_sharing: true }
* ```
*/
Expand Down
17 changes: 8 additions & 9 deletions clients/privacy-center/cypress/e2e/consent-banner-tcf.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ describe("Fides-js TCF", () => {
cy.getByTestId("consent-modal").within(() => {
cy.get("button").contains("Opt in to all").click();
});
cy.get("@FidesUpdated").should("have.been.calledTwice");
cy.get("@FidesUpdated").should("have.been.calledOnce");
cy.window().then((win) => {
win.__tcfapi("getTCData", 2, cy.stub().as("getTCData"));
cy.get("@getTCData")
Expand Down Expand Up @@ -1331,12 +1331,12 @@ describe("Fides-js TCF", () => {

describe("setting fields", () => {
it("can opt in to all and set legitimate interests", () => {
cy.get("@FidesUpdated").should("have.been.calledOnce");
cy.get("@FidesUpdated").should("not.have.been.called");
cy.getByTestId("consent-modal").within(() => {
cy.get("button").contains("Opt in to all").click();
});
// On slow connections, we should explicitly wait for FidesUpdated
cy.get("@FidesUpdated").should("have.been.calledTwice");
cy.get("@FidesUpdated").should("have.been.calledOnce");
cy.get("@TCFEvent")
.its("lastCall.args")
.then(([tcData, success]) => {
Expand Down Expand Up @@ -1399,7 +1399,7 @@ describe("Fides-js TCF", () => {
cy.getByTestId("consent-modal").within(() => {
cy.get("button").contains("Opt in to all").click();
});
cy.get("@FidesUpdated").should("have.been.calledTwice");
cy.get("@FidesUpdated").should("have.been.calledOnce");
cy.get("@TCFEvent2")
.its("lastCall.args")
.then(([tcData, success]) => {
Expand Down Expand Up @@ -2191,8 +2191,8 @@ describe("Fides-js TCF", () => {
cy.get("button").contains("Save").click();
cy.wait("@patchPrivacyPreference");
cy.get("@FidesUpdated")
.should("have.been.calledTwice")
.its("secondCall.args.0.detail.fides_string")
.should("have.been.calledOnce")
.its("lastCall.args.0.detail.fides_string")
.then((fidesString) => {
const parts = fidesString.split(",");
expect(parts.length).to.eql(2);
Expand Down Expand Up @@ -2221,7 +2221,7 @@ describe("Fides-js TCF", () => {
});
cy.get("button").contains("Save").click();
cy.wait("@patchPrivacyPreference");
cy.get("@FidesUpdated").should("have.been.calledTwice");
cy.get("@FidesUpdated").should("have.been.calledOnce");
// Call getTCData
cy.window().then((win) => {
win.__tcfapi("getTCData", 2, cy.stub().as("getTCData"));
Expand Down Expand Up @@ -2271,8 +2271,7 @@ describe("Fides-js TCF", () => {
});

cy.get("@FidesInitialized")
.should("have.been.calledOnce")
.its("firstCall.args.0.detail.tcf_consent")
.its("lastCall.args.0.detail.tcf_consent")
.then((tcfConsent) => {
// TC string setting worked
expect(tcfConsent.purpose_consent_preferences).to.eql({
Expand Down
105 changes: 30 additions & 75 deletions clients/privacy-center/cypress/e2e/consent-banner.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,7 @@ describe("Consent banner", () => {

it("can remove all cookies when rejecting all", () => {
cy.contains("button", "Reject Test").click();
cy.get("@FidesUpdated").should("have.been.calledTwice");
cy.get("@FidesUpdated").should("have.been.calledOnce");
cy.getAllCookies().then((allCookies) => {
expect(allCookies.map((c) => c.name)).to.eql([CONSENT_COOKIE_NAME]);
});
Expand All @@ -418,7 +418,7 @@ describe("Consent banner", () => {
// opt out of the first notice
cy.getByTestId("toggle-one").click();
cy.getByTestId("Save test-btn").click();
cy.get("@FidesUpdated").should("have.been.calledTwice");
cy.get("@FidesUpdated").should("have.been.calledOnce");
cy.getAllCookies().then((allCookies) => {
expect(allCookies.map((c) => c.name)).to.eql([
CONSENT_COOKIE_NAME,
Expand Down Expand Up @@ -1090,7 +1090,7 @@ describe("Consent banner", () => {

// NOTE: See definition of cy.visitConsentDemo in commands.ts for where we
// register listeners for these window events
it("emits both a FidesInitialized and FidesUpdated event when initialized", () => {
it("emits a FidesInitialized but not a FidesUpdated event when initialized", () => {
cy.window()
.its("Fides")
.its("consent")
Expand All @@ -1105,51 +1105,47 @@ describe("Consent banner", () => {
[PRIVACY_NOTICE_KEY_1]: false,
[PRIVACY_NOTICE_KEY_2]: true,
});
cy.get("@FidesUpdated")
.should("have.been.calledOnce")
.its("firstCall.args.0.detail.consent")
.should("deep.equal", {
[PRIVACY_NOTICE_KEY_1]: false,
[PRIVACY_NOTICE_KEY_2]: true,
});
cy.get("@FidesUpdated").should("not.have.been.called");
cy.get("@FidesUIChanged").should("not.have.been.called");
});

describe("when preferences are changed / saved", () => {
it("emits another FidesUpdated event when reject all is clicked", () => {
it("emits a FidesUpdated event when reject all is clicked", () => {
cy.contains("button", "Reject Test").should("be.visible").click();
cy.get("@FidesUIChanged").should("not.have.been.called");
cy.get("@FidesUpdated")
.should("have.been.calledTwice")
// First call should be from initialization, before the user rejects all
cy.get("@FidesInitialized")
// First event, before the user rejects all
.should("have.been.calledOnce")
.its("firstCall.args.0.detail.consent")
.should("deep.equal", {
[PRIVACY_NOTICE_KEY_1]: false,
[PRIVACY_NOTICE_KEY_2]: true,
});
cy.get("@FidesUpdated")
// Second call is when the user rejects all
.its("secondCall.args.0.detail.consent")
// Update event, when the user rejects all
.should("have.been.calledOnce")
.its("firstCall.args.0.detail.consent")
.should("deep.equal", {
[PRIVACY_NOTICE_KEY_1]: false,
[PRIVACY_NOTICE_KEY_2]: true,
});
});

it("emits another FidesUpdated event when accept all is clicked", () => {
it("emits a FidesUpdated event when accept all is clicked", () => {
cy.contains("button", "Accept Test").should("be.visible").click();
cy.get("@FidesUIChanged").should("not.have.been.called");
cy.get("@FidesUpdated")
.should("have.been.calledTwice")
// First call should be from initialization, before the user accepts all
cy.get("@FidesInitialized")
// First event, before the user accepts all
.should("have.been.calledOnce")
.its("firstCall.args.0.detail.consent")
.should("deep.equal", {
[PRIVACY_NOTICE_KEY_1]: false,
[PRIVACY_NOTICE_KEY_2]: true,
});
cy.get("@FidesUpdated")
// Second call is when the user accepts all
.its("secondCall.args.0.detail.consent")
// Update event, when the user accepts all
.should("have.been.calledOnce")
.its("firstCall.args.0.detail.consent")
.should("deep.equal", {
[PRIVACY_NOTICE_KEY_1]: true,
[PRIVACY_NOTICE_KEY_2]: true,
Expand All @@ -1163,17 +1159,18 @@ describe("Consent banner", () => {
cy.getByTestId("toggle-Test privacy notice").click();
cy.getByTestId("consent-modal").contains("Save").click();
cy.get("@FidesUIChanged").should("have.been.calledOnce");
cy.get("@FidesUpdated")
.should("have.been.calledTwice")
// First call should be from initialization, before the user saved preferences
cy.get("@FidesInitialized")
// First event, before the user saved preferences
.should("have.been.calledOnce")
.its("firstCall.args.0.detail.consent")
.should("deep.equal", {
[PRIVACY_NOTICE_KEY_1]: false,
[PRIVACY_NOTICE_KEY_2]: true,
});
cy.get("@FidesUpdated")
// Second call is when the user saved preferences and opted-in to the first notice
.its("secondCall.args.0.detail.consent")
// Update event, when the user saved preferences and opted-in to the first notice
.should("have.been.calledOnce")
.its("firstCall.args.0.detail.consent")
.should("deep.equal", {
[PRIVACY_NOTICE_KEY_1]: true,
[PRIVACY_NOTICE_KEY_2]: true,
Expand Down Expand Up @@ -1255,21 +1252,14 @@ describe("Consent banner", () => {
[PRIVACY_NOTICE_KEY_2]: true,
});
cy.get("@FidesInitialized")
.should("have.been.calledOnce")
.its("firstCall.args.0.detail.consent")
.should("deep.equal", {
data_sales: false,
tracking: false,
analytics: true,
});
cy.get("@FidesUpdated")
.should("have.been.calledTwice")
.its("firstCall.args.0.detail.consent")
.should("deep.equal", {
data_sales: false,
tracking: false,
analytics: true,
});
cy.get("@FidesUpdated")
cy.get("@FidesInitialized")
.its("secondCall.args.0.detail.consent")
.should("deep.equal", {
[PRIVACY_NOTICE_KEY_1]: false,
Expand Down Expand Up @@ -1316,21 +1306,14 @@ describe("Consent banner", () => {
[PRIVACY_NOTICE_KEY_2]: true,
});
cy.get("@FidesInitialized")
.should("have.been.calledOnce")
.its("firstCall.args.0.detail.consent")
.should("deep.equal", {
data_sales: false,
tracking: false,
analytics: true,
});
cy.get("@FidesUpdated")
.should("have.been.calledTwice")
.its("firstCall.args.0.detail.consent")
.should("deep.equal", {
data_sales: false,
tracking: false,
analytics: true,
});
cy.get("@FidesUpdated")
cy.get("@FidesInitialized")
.its("secondCall.args.0.detail.consent")
.should("deep.equal", {
[PRIVACY_NOTICE_KEY_1]: false,
Expand Down Expand Up @@ -1377,27 +1360,13 @@ describe("Consent banner", () => {
analytics: true,
});
cy.get("@FidesInitialized")
.should("have.been.calledOnce")
.its("firstCall.args.0.detail.consent")
.should("deep.equal", {
data_sales: false,
tracking: false,
analytics: true,
});
cy.get("@FidesUpdated")
.should("have.been.calledTwice")
.its("firstCall.args.0.detail.consent")
.should("deep.equal", {
data_sales: false,
tracking: false,
analytics: true,
});
cy.get("@FidesUpdated")
.its("secondCall.args.0.detail.consent")
.should("deep.equal", {
data_sales: false,
tracking: false,
analytics: true,
});
});
});

Expand Down Expand Up @@ -1438,27 +1407,13 @@ describe("Consent banner", () => {
analytics: true,
});
cy.get("@FidesInitialized")
.should("have.been.calledOnce")
.its("firstCall.args.0.detail.consent")
.should("deep.equal", {
data_sales: false,
tracking: false,
analytics: true,
});
cy.get("@FidesUpdated")
.should("have.been.calledTwice")
.its("firstCall.args.0.detail.consent")
.should("deep.equal", {
data_sales: false,
tracking: false,
analytics: true,
});
cy.get("@FidesUpdated")
.its("secondCall.args.0.detail.consent")
.should("deep.equal", {
data_sales: false,
tracking: false,
analytics: true,
});
});
});
});
Expand Down

0 comments on commit 561f828

Please sign in to comment.