Skip to content

Commit

Permalink
Merge Full TCF in to window.Fides.experience after successful fetch (
Browse files Browse the repository at this point in the history
  • Loading branch information
gilluminate authored Feb 5, 2025
1 parent f831741 commit deef26b
Show file tree
Hide file tree
Showing 5 changed files with 111 additions and 51 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ Changes can also be flagged with a GitHub label for tracking purposes. The URL o
- Fixed `fides annotate dataset` command enters incorrect value on the `direction` field. [#5727](https://github.com/ethyca/fides/pull/5727)
- Fixed Bigquery flakey tests. [#5713](https://github.com/ethyca/fides/pull/5713)
- Fixed breadcrumb navigation issues in data catalog view [#5717](https://github.com/ethyca/fides/pull/5717)
- Fixed `window.Fides.experience` of FidesJS to be a merged version of the minimal and full experience. [#5726](https://github.com/ethyca/fides/pull/5726)

## [2.54.0](https://github.com/ethyca/fides/compare/2.53.0...2.54.0)

Expand Down
38 changes: 27 additions & 11 deletions clients/fides-js/src/components/tcf/TcfOverlay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ import {
PrivacyExperienceMinimal,
ServingComponent,
} from "../../lib/consent-types";
import { isPrivacyExperience } from "../../lib/consent-utils";
import {
experienceIsValid,
isPrivacyExperience,
} from "../../lib/consent-utils";
import { dispatchFidesEvent } from "../../lib/events";
import { useNoticesServed } from "../../lib/hooks";
import {
Expand Down Expand Up @@ -141,6 +144,7 @@ export const TcfOverlay = ({
isGVLLangLoading = false;
});
}
fidesDebugger("Fetching full TCF experience...");
fetchExperience({
userLocationString: fidesRegionString,
fidesApiUrl: options.fidesApiUrl,
Expand All @@ -151,17 +155,29 @@ export const TcfOverlay = ({
if (isPrivacyExperience(result)) {
// include user preferences from the cookie
const userPrefs = buildUserPrefs(result, cookie);
const fullExperience: PrivacyExperience = { ...result, ...userPrefs };

setExperience(fullExperience);
loadMessagesFromExperience(i18n, fullExperience, translationOverrides);
if (!userlocale || bestLocale === defaultLocale) {
// English (default) GVL translations are part of the full experience, so we load them here.
loadGVLMessagesFromExperience(i18n, fullExperience);
} else {
setCurrentLocale(bestLocale);
if (!isGVLLangLoading) {
setIsI18nLoading(false);
if (experienceIsValid(result)) {
const fullExperience: PrivacyExperience = { ...result, ...userPrefs };
window.Fides.experience = {
...window.Fides.experience,
...fullExperience,
};
window.Fides.experience.minimal_tcf = false;

setExperience(fullExperience);
loadMessagesFromExperience(
i18n,
fullExperience,
translationOverrides,
);
if (!userlocale || bestLocale === defaultLocale) {
// English (default) GVL translations are part of the full experience, so we load them here.
loadGVLMessagesFromExperience(i18n, fullExperience);
} else {
setCurrentLocale(bestLocale);
if (!isGVLLangLoading) {
setIsI18nLoading(false);
}
}
}
}
Expand Down
116 changes: 80 additions & 36 deletions clients/privacy-center/cypress/e2e/consent-banner-tcf.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
FidesCookie,
FidesEndpointPaths,
PrivacyExperience,
PrivacyExperienceMinimal,
} from "fides-js";
import { NoticeConsent } from "fides-js/src/lib/consent-types";
import { FIDES_SEPARATOR } from "fides-js/src/lib/tcf/constants";
Expand Down Expand Up @@ -215,6 +216,49 @@ describe("Fides-js TCF", () => {
});
});

describe("Payload optimization", () => {
beforeEach(() => {
cy.getCookie(CONSENT_COOKIE_NAME).should("not.exist");
stubTCFExperience({});
});
it("merges full experience with minimal after successful fetch", () => {
cy.window().then((win) => {
cy.fixture("consent/experience_tcf.json").then((payload) => {
cy.wait("@getPrivacyExperience");
expect(
(win.Fides.experience as PrivacyExperienceMinimal)
.tcf_purpose_consent_ids,
).to.have.length(11);
expect((win.Fides.experience as any).tcf_purpose_consents).to.not
.exist;
cy.waitUntilFidesInitialized().then(() => {
const experience = payload.items[0];
const updatedExperience = {
...experience,
tcf_purpose_consents: [],
};
stubTCFExperience({
experienceFullOverride: updatedExperience,
});
cy.wait("@getPrivacyExperience");
expect(
(
win.Fides.experience as PrivacyExperience &
PrivacyExperienceMinimal
).tcf_purpose_consent_ids,
).to.have.length(11);
expect(
(
win.Fides.experience as PrivacyExperience &
PrivacyExperienceMinimal
).tcf_purpose_consents,
).to.exist.to.have.length(4);
});
});
});
});
});

describe("initial layer", () => {
beforeEach(() => {
cy.getCookie(CONSENT_COOKIE_NAME).should("not.exist");
Expand All @@ -223,6 +267,7 @@ describe("Fides-js TCF", () => {
fixture: "consent/notices_served_tcf.json",
}).as("patchNoticesServed");
});

it("can render purposes in the initial layer", () => {
cy.get("div#fides-banner").within(() => {
cy.contains(PURPOSE_2.name);
Expand Down Expand Up @@ -511,6 +556,7 @@ describe("Fides-js TCF", () => {
beforeEach(() => {
cy.getCookie(CONSENT_COOKIE_NAME).should("not.exist");
stubTCFExperience({});
cy.wait("@getPrivacyExperience");
cy.intercept("PATCH", `${API_URL}${FidesEndpointPaths.NOTICES_SERVED}`, {
fixture: "consent/notices_served_tcf.json",
}).as("patchNoticesServed");
Expand Down Expand Up @@ -1141,44 +1187,42 @@ describe("Fides-js TCF", () => {

stubTCFExperience({
stubOptions: { apiOptions },
}).then((result) => {
const privacyExperience = result.response.body.items[0];
cy.waitUntilFidesInitialized().then(() => {
cy.get("div#fides-banner").within(() => {
cy.get("#fides-button-group").within(() => {
cy.get("button").contains("Manage preferences").click();
});
});
cy.waitUntilFidesInitialized().then(() => {
cy.get("div#fides-banner").within(() => {
cy.get("#fides-button-group").within(() => {
cy.get("button").contains("Manage preferences").click();
});
cy.getByTestId("consent-modal").within(() => {
cy.get("button").contains("Opt out of all").click();
cy.get("@FidesUpdated")
.should("have.been.calledOnce")
.its("lastCall.args.0.detail.extraDetails.consentMethod")
.then((consentMethod) => {
expect(consentMethod).to.eql(ConsentMethod.REJECT);
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
expect(spyObject).to.be.called;
const spy = spyObject.getCalls();
const { args } = spy[0];
expect(args[0]).to.equal(ConsentMethod.REJECT);
expect(args[1]).to.be.a("object");
// the TC str is dynamically updated upon save preferences with diff timestamp, so we do a fuzzy match
expect(args[2]).to.contain("AA,1~");
expect(args[3]).to.be.a("object");
// timeout means API call not made, which is expected
cy.on("fail", (error) => {
if (error.message.indexOf("Timed out retrying") !== 0) {
throw error;
}
});
// check that preferences aren't sent to Fides API
cy.wait("@patchPrivacyPreference", {
requestTimeout: 100,
}).then((xhr) => {
assert.isNull(xhr?.response?.body);
});
});
cy.getByTestId("consent-modal").within(() => {
cy.get("button").contains("Opt out of all").click();
cy.get("@FidesUpdated")
.should("have.been.calledOnce")
.its("lastCall.args.0.detail.extraDetails.consentMethod")
.then((consentMethod) => {
expect(consentMethod).to.eql(ConsentMethod.REJECT);
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
expect(spyObject).to.be.called;
const spy = spyObject.getCalls();
const { args } = spy[0];
expect(args[0]).to.equal(ConsentMethod.REJECT);
expect(args[1]).to.be.a("object");
// the TC str is dynamically updated upon save preferences with diff timestamp, so we do a fuzzy match
expect(args[2]).to.contain("AA,1~");
expect(args[3]).to.be.a("object");
// timeout means API call not made, which is expected
cy.on("fail", (error) => {
if (error.message.indexOf("Timed out retrying") !== 0) {
throw error;
}
});
});
// check that preferences aren't sent to Fides API
cy.wait("@patchPrivacyPreference", {
requestTimeout: 100,
}).then((xhr) => {
assert.isNull(xhr?.response?.body);
});
});
});
});
});
Expand Down
2 changes: 2 additions & 0 deletions clients/privacy-center/cypress/e2e/consent-notices.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -474,7 +474,9 @@ describe("Privacy notice driven consent", () => {
cy.wait("@getExperience");

cy.getByTestId("consent-item-pri_notice-advertising-000").click();
cy.getByTestId("toggle-Weekly Newsletter").should("be.visible");
cy.getByTestId("toggle-Weekly Newsletter").getToggle().check();
cy.getByTestId("toggle-Monthly Newsletter").should("be.visible");
cy.getByTestId("toggle-Monthly Newsletter").getToggle().check();

cy.getByTestId("save-btn").click();
Expand Down
5 changes: 1 addition & 4 deletions clients/privacy-center/cypress/support/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Cypress.Commands.add("getByTestId", (selector, ...args) =>
cy.get(`[data-testid='${selector}']`, ...args),
);

Cypress.Commands.add("getToggle", (...args) =>
Cypress.Commands.add("getToggle", (_, ...args) =>
cy.get(`input[type="checkbox"]`, ...args),
);

Expand Down Expand Up @@ -121,9 +121,6 @@ Cypress.Commands.add(
visitOptions.qs = queryParams;
}
cy.visit("/fides-js-components-demo.html", visitOptions);
if (options?.options?.tcfEnabled) {
cy.wait("@getPrivacyExperience");
}
},
);

Expand Down

0 comments on commit deef26b

Please sign in to comment.