diff --git a/CHANGELOG.md b/CHANGELOG.md index 66e3a913693..ebf2e53219f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ The types of changes are: ## [Unreleased](https://github.com/ethyca/fides/compare/2.22.0...main) - Added support for 3 additional config variables in Fides.js: fidesEmbed, fidesDisableSaveApi, and fidesTcString [#4262](https://github.com/ethyca/fides/pull/4262) +- Added support for fidesEmbed, fidesDisableSaveApi, and fidesTcString to be passed into Fides.js via query param, cookie, or window object [#4297](https://github.com/ethyca/fides/pull/4297) ### Added - Added a `FidesPreferenceToggled` event to Fides.js to track when user preferences change without being saved [#4253](https://github.com/ethyca/fides/pull/4253) diff --git a/clients/fides-js/rollup.config.mjs b/clients/fides-js/rollup.config.mjs index 541cf8c8792..14f6aceedde 100644 --- a/clients/fides-js/rollup.config.mjs +++ b/clients/fides-js/rollup.config.mjs @@ -14,7 +14,7 @@ const GZIP_SIZE_ERROR_KB = 22; // fail build if bundle size exceeds this const GZIP_SIZE_WARN_KB = 15; // log a warning if bundle size exceeds this // TCF -const GZIP_SIZE_TCF_ERROR_KB = 41; +const GZIP_SIZE_TCF_ERROR_KB = 42; const GZIP_SIZE_TCF_WARN_KB = 35; const preactAliases = { diff --git a/clients/fides-js/src/fides-tcf.ts b/clients/fides-js/src/fides-tcf.ts index 40cbcea1162..a8dc055326a 100644 --- a/clients/fides-js/src/fides-tcf.ts +++ b/clients/fides-js/src/fides-tcf.ts @@ -52,6 +52,8 @@ import { shopify } from "./integrations/shopify"; import { FidesConfig, + FidesOptionOverrides, + OverrideOptions, PrivacyExperience, UserConsentPreference, } from "./lib/consent-types"; @@ -60,6 +62,7 @@ import { generateFidesString, initializeCmpApi } from "./lib/tcf"; import { getInitialCookie, getInitialFides, + getOverrideFidesOptions, initialize, } from "./lib/initialize"; import type { Fides } from "./lib/initialize"; @@ -71,6 +74,7 @@ import { hasSavedTcfPreferences, isNewFidesCookie, isPrivacyExperience, + tcfConsentCookieObjHasSomeConsentSet, transformTcfPreferencesToCookieKeys, transformUserPreferenceToBoolean, } from "./fides"; @@ -96,6 +100,9 @@ declare global { callback: (tcData: TCData, success: boolean) => void, parameter?: number | string ) => void; + config: { + fides: OverrideOptions; + }; } } @@ -164,6 +171,10 @@ const updateCookie = async ( * Initialize the global Fides object with the given configuration values */ const init = async (config: FidesConfig) => { + const overrideOptions: Partial = + getOverrideFidesOptions(); + // eslint-disable-next-line no-param-reassign + config.options = { ...config.options, ...overrideOptions }; const cookie = getInitialCookie(config); if (config.options.fidesString) { // If a fidesString is explicitly passed in, we override the associated cookie props, which are then used to @@ -178,7 +189,7 @@ const init = async (config: FidesConfig) => { config.options.debug ); } else if ( - cookie.tcf_consent && + tcfConsentCookieObjHasSomeConsentSet(cookie.tcf_consent) && !cookie.fides_string && isPrivacyExperience(config.experience) && experienceIsValid(config.experience, config.options) diff --git a/clients/fides-js/src/fides.ts b/clients/fides-js/src/fides.ts index 45bd64b4db1..5fbbb07b5a2 100644 --- a/clients/fides-js/src/fides.ts +++ b/clients/fides-js/src/fides.ts @@ -53,7 +53,12 @@ import { buildCookieConsentForExperiences, isNewFidesCookie, } from "./lib/cookie"; -import { FidesConfig, PrivacyExperience } from "./lib/consent-types"; +import { + FidesConfig, + FidesOptionOverrides, + OverrideOptions, + PrivacyExperience, +} from "./lib/consent-types"; import { dispatchFidesEvent } from "./lib/events"; @@ -61,6 +66,7 @@ import { initialize, getInitialCookie, getInitialFides, + getOverrideFidesOptions, } from "./lib/initialize"; import type { Fides } from "./lib/initialize"; @@ -70,6 +76,9 @@ import { getConsentContext } from "./lib/consent-context"; declare global { interface Window { Fides: Fides; + config: { + fides: OverrideOptions; + }; } } @@ -95,6 +104,10 @@ const updateCookie = async ( * Initialize the global Fides object with the given configuration values */ const init = async (config: FidesConfig) => { + const overrideOptions: Partial = + getOverrideFidesOptions(); + // eslint-disable-next-line no-param-reassign + config.options = { ...config.options, ...overrideOptions }; const cookie = getInitialCookie(config); const initialFides = getInitialFides({ ...config, cookie }); if (initialFides) { diff --git a/clients/fides-js/src/lib/consent-constants.ts b/clients/fides-js/src/lib/consent-constants.ts new file mode 100644 index 00000000000..0b0ea7cfbad --- /dev/null +++ b/clients/fides-js/src/lib/consent-constants.ts @@ -0,0 +1,33 @@ +import { FidesOptionOverrides, OverrideOptions } from "./consent-types"; + +// Regex to validate a location string, which must: +// 1) Start with a 2-3 character country code (e.g. "US") +// 2) Optionally end with a 2-3 character region code (e.g. "CA") +// 3) Separated by a dash (e.g. "US-CA") +export const VALID_ISO_3166_LOCATION_REGEX = /^\w{2,3}(-\w{2,3})?$/; + +export const FIDES_OVERRIDE_OPTIONS_VALIDATOR_MAP: { + fidesOption: keyof FidesOptionOverrides; + fidesOptionType: "string" | "boolean"; + fidesOverrideKey: keyof OverrideOptions; + validationRegex: RegExp; +}[] = [ + { + fidesOption: "fidesEmbed", + fidesOptionType: "boolean", + fidesOverrideKey: "fides_embed", + validationRegex: /^(true|false)$/, + }, + { + fidesOption: "fidesDisableSaveApi", + fidesOptionType: "boolean", + fidesOverrideKey: "fides_disable_save_api", + validationRegex: /^(true|false)$/, + }, + { + fidesOption: "fidesString", + fidesOptionType: "string", + fidesOverrideKey: "fides_string", + validationRegex: /(.*)/, + }, +]; diff --git a/clients/fides-js/src/lib/consent-types.ts b/clients/fides-js/src/lib/consent-types.ts index 3b7405b9de1..3a72a454d6d 100644 --- a/clients/fides-js/src/lib/consent-types.ts +++ b/clients/fides-js/src/lib/consent-types.ts @@ -201,11 +201,16 @@ export type UserGeolocation = { region?: string; // "NY" }; -// Regex to validate a location string, which must: -// 1) Start with a 2-3 character country code (e.g. "US") -// 2) Optionally end with a 2-3 character region code (e.g. "CA") -// 3) Separated by a dash (e.g. "US-CA") -export const VALID_ISO_3166_LOCATION_REGEX = /^\w{2,3}(-\w{2,3})?$/; +export type OverrideOptions = { + fides_string: string; + fides_disable_save_api: boolean; + fides_embed: boolean; +}; + +export type FidesOptionOverrides = Pick< + FidesOptions, + "fidesString" | "fidesDisableSaveApi" | "fidesEmbed" +>; export enum ButtonType { PRIMARY = "primary", diff --git a/clients/fides-js/src/lib/consent-utils.ts b/clients/fides-js/src/lib/consent-utils.ts index 8a543d30c76..e1ef7d029ac 100644 --- a/clients/fides-js/src/lib/consent-utils.ts +++ b/clients/fides-js/src/lib/consent-utils.ts @@ -9,10 +9,10 @@ import { PrivacyNotice, UserConsentPreference, UserGeolocation, - VALID_ISO_3166_LOCATION_REGEX, } from "./consent-types"; import { EXPERIENCE_KEYS_WITH_PREFERENCES } from "./tcf/constants"; import { TCFPurposeConsentRecord } from "./tcf/types"; +import { VALID_ISO_3166_LOCATION_REGEX } from "./consent-constants"; /** * Wrapper around 'console.log' that only logs output when the 'debug' banner diff --git a/clients/fides-js/src/lib/cookie.ts b/clients/fides-js/src/lib/cookie.ts index a5b069fadff..8a0cf466a0d 100644 --- a/clients/fides-js/src/lib/cookie.ts +++ b/clients/fides-js/src/lib/cookie.ts @@ -20,6 +20,7 @@ import { } from "./consent-utils"; import type { TcfCookieConsent, TcfSavePreferences } from "./tcf/types"; import { TCF_KEY_MAP } from "./tcf/constants"; +import { TcfCookieKeyConsent } from "./tcf/types"; /** * Store the user's consent preferences on the cookie, as key -> boolean pairs, e.g. @@ -81,6 +82,17 @@ const CODEC: Types.CookieCodecConfig = { encodeValue: encodeURIComponent, }; +export const tcfConsentCookieObjHasSomeConsentSet = ( + tcf_consent: TcfCookieConsent | undefined +): boolean => { + if (!tcf_consent) { + return false; + } + return Object.values(tcf_consent).some( + (val: TcfCookieKeyConsent) => Object.keys(val).length >= 0 + ); +}; + /** * Each cookie will be assigned an autogenerated user/device ID, to match user's * consent preferences between the browser and the server. This is a randomly @@ -118,6 +130,12 @@ export const makeFidesCookie = (consent?: CookieKeyConsent): FidesCookie => { }; }; +/** + * Retrieve cookie by name + */ +export const getCookieByName = (cookieName: string): string | undefined => + getCookie(cookieName, CODEC); + /** * Attempt to read, parse, and return the current Fides cookie from the browser. * If one doesn't exist, make a new default cookie (including generating a new @@ -138,7 +156,7 @@ export const getOrMakeFidesCookie = ( } // Check for an existing cookie for this device - const cookieString = getCookie(CONSENT_COOKIE_NAME, CODEC); + const cookieString = getCookieByName(CONSENT_COOKIE_NAME); if (!cookieString) { debugLog( debug, diff --git a/clients/fides-js/src/lib/initialize.ts b/clients/fides-js/src/lib/initialize.ts index a1c003ba730..fcfdf4c3fb3 100644 --- a/clients/fides-js/src/lib/initialize.ts +++ b/clients/fides-js/src/lib/initialize.ts @@ -9,6 +9,7 @@ import { CookieKeyConsent, CookieMeta, FidesCookie, + getCookieByName, getOrMakeFidesCookie, isNewFidesCookie, makeConsentDefaultsLegacy, @@ -20,6 +21,7 @@ import { ConsentMethod, EmptyExperience, FidesConfig, + FidesOptionOverrides, FidesOptions, PrivacyExperience, SaveConsentPreference, @@ -40,6 +42,7 @@ import { updateConsentPreferences } from "./preferences"; import { resolveConsentValue } from "./consent-value"; import { initOverlay } from "./consent"; import { TcfCookieConsent } from "./tcf/types"; +import { FIDES_OVERRIDE_OPTIONS_VALIDATOR_MAP } from "./consent-constants"; export type Fides = { consent: CookieKeyConsent; @@ -143,6 +146,35 @@ const automaticallyApplyGPCPreferences = ({ } }; +/** + * Gets and validates Fides override options provided through URL query params, cookie or window obj. + */ +export const getOverrideFidesOptions = (): Partial => { + const overrideOptions: Partial = {}; + if (typeof window !== "undefined") { + const params = new URLSearchParams(document.location.search); + FIDES_OVERRIDE_OPTIONS_VALIDATOR_MAP.forEach( + ({ fidesOption, fidesOptionType, fidesOverrideKey, validationRegex }) => { + // look for override options on URL query params, window obj, and cookie + const queryParamOverride: string | null = params.get(fidesOverrideKey); + const windowObjOverride: string | boolean | undefined = window.config + ?.fides + ? window.config?.fides[fidesOverrideKey] + : undefined; + const cookieOverride: string | undefined = + getCookieByName(fidesOverrideKey); + const value = queryParamOverride || windowObjOverride || cookieOverride; + if (value && validationRegex.test(value.toString())) { + // coerce to expected type in FidesOptions + overrideOptions[fidesOption] = + fidesOptionType === "string" ? value : JSON.parse(value.toString()); + } + } + ); + } + return overrideOptions; +}; + /** * Get the initial Fides cookie based on legacy consent values * as well as any preferences stored in existing cookies diff --git a/clients/privacy-center/cypress/e2e/consent-banner-tcf.cy.ts b/clients/privacy-center/cypress/e2e/consent-banner-tcf.cy.ts index 1f2b3c570f0..55e9a782eb0 100644 --- a/clients/privacy-center/cypress/e2e/consent-banner-tcf.cy.ts +++ b/clients/privacy-center/cypress/e2e/consent-banner-tcf.cy.ts @@ -742,11 +742,114 @@ describe("Fides-js TCF", () => { }); }); }); + it("skips saving preferences to API when disable save is set via cookie", () => { + cy.getCookie(CONSENT_COOKIE_NAME).should("not.exist"); + cy.getCookie("fides_disable_save_api").should("not.exist"); + cy.setCookie("fides_disable_save_api", "true"); + cy.fixture("consent/experience_tcf.json").then((experience) => { + stubConfig({ + options: { + isOverlayEnabled: true, + tcfEnabled: true, + }, + experience: experience.items[0], + }); + }); + cy.waitUntilFidesInitialized().then(() => { + cy.get("#fides-modal-link").click(); + cy.getByTestId("consent-modal").within(() => { + cy.get("button").contains("Opt out of all").click(); + // 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: 500, + }).then((xhr) => { + assert.isNull(xhr?.response?.body); + }); + }); + }); + }); + it("skips saving preferences to API when disable save is set via query param", () => { + cy.getCookie("fides_string").should("not.exist"); + cy.fixture("consent/experience_tcf.json").then((experience) => { + stubConfig( + { + options: { + isOverlayEnabled: true, + tcfEnabled: true, + }, + experience: experience.items[0], + }, + null, + null, + { fides_disable_save_api: true } + ); + }); + cy.waitUntilFidesInitialized().then(() => { + cy.get("#fides-modal-link").click(); + cy.getByTestId("consent-modal").within(() => { + cy.get("button").contains("Opt out of all").click(); + // 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: 500, + }).then((xhr) => { + assert.isNull(xhr?.response?.body); + }); + }); + }); + }); + it("skips saving preferences to API when disable save is set via window obj", () => { + cy.getCookie("fides_string").should("not.exist"); + cy.fixture("consent/experience_tcf.json").then((experience) => { + stubConfig( + { + options: { + isOverlayEnabled: true, + tcfEnabled: true, + }, + experience: experience.items[0], + }, + null, + null, + null, + { fides_disable_save_api: true } + ); + }); + cy.waitUntilFidesInitialized().then(() => { + cy.get("#fides-modal-link").click(); + cy.getByTestId("consent-modal").within(() => { + cy.get("button").contains("Opt out of all").click(); + // 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: 500, + }).then((xhr) => { + assert.isNull(xhr?.response?.body); + }); + }); + }); + }); }); }); describe("second layer embedded", () => { - beforeEach(() => { + it("automatically renders the second layer and can render tabs", () => { cy.getCookie(CONSENT_COOKIE_NAME).should("not.exist"); cy.fixture("consent/experience_tcf.json").then((experience) => { stubConfig({ @@ -758,8 +861,6 @@ describe("Fides-js TCF", () => { experience: experience.items[0], }); }); - }); - it("automatically renders the second layer and can render tabs", () => { cy.get("#fides-tab-Purposes"); // Purposes cy.getByTestId("toggle-Purposes").within(() => { @@ -796,6 +897,17 @@ describe("Fides-js TCF", () => { }); }); it("can opt in to some and opt out of others", () => { + cy.getCookie(CONSENT_COOKIE_NAME).should("not.exist"); + cy.fixture("consent/experience_tcf.json").then((experience) => { + stubConfig({ + options: { + isOverlayEnabled: true, + tcfEnabled: true, + fidesEmbed: true, + }, + experience: experience.items[0], + }); + }); cy.getByTestId("consent-modal").within(() => { cy.getByTestId(`toggle-${PURPOSE_4.name}-consent`).click(); cy.get("#fides-tab-Features").click(); @@ -867,6 +979,89 @@ describe("Fides-js TCF", () => { ); }); }); + it("automatically renders the second layer when fidesEmbed is set via cookie", () => { + cy.getCookie(CONSENT_COOKIE_NAME).should("not.exist"); + cy.getCookie("fides_embed").should("not.exist"); + cy.setCookie("fides_embed", "true"); + cy.fixture("consent/experience_tcf.json").then((experience) => { + stubConfig({ + options: { + isOverlayEnabled: true, + tcfEnabled: true, + }, + experience: experience.items[0], + }); + }); + // spot check a couple UI elements + cy.get("#fides-tab-Purposes"); + // Purposes + cy.getByTestId("toggle-Purposes").within(() => { + cy.get("input").should("be.checked"); + }); + // Vendors + cy.get("#fides-tab-Vendors").click(); + cy.getByTestId(`toggle-${SYSTEM_1.name}`).within(() => { + cy.get("input").should("be.checked"); + }); + }); + it("automatically renders the second layer when fidesEmbed is set via query param", () => { + cy.getCookie(CONSENT_COOKIE_NAME).should("not.exist"); + cy.fixture("consent/experience_tcf.json").then((experience) => { + stubConfig( + { + options: { + isOverlayEnabled: true, + tcfEnabled: true, + }, + experience: experience.items[0], + }, + null, + null, + { fides_embed: true } + ); + }); + // spot check a couple UI elements + cy.get("#fides-tab-Purposes"); + // Purposes + cy.getByTestId("toggle-Purposes").within(() => { + cy.get("input").should("be.checked"); + }); + // Vendors + cy.get("#fides-tab-Vendors").click(); + cy.getByTestId(`toggle-${SYSTEM_1.name}`).within(() => { + cy.get("input").should("be.checked"); + }); + }); + it("automatically renders the second layer when fidesEmbed is set via window obj", () => { + cy.getCookie("fides_string").should("not.exist"); + cy.getCookie(CONSENT_COOKIE_NAME).should("not.exist"); + cy.fixture("consent/experience_tcf.json").then((experience) => { + stubConfig( + { + options: { + isOverlayEnabled: true, + tcfEnabled: true, + }, + experience: experience.items[0], + }, + null, + null, + null, + { fides_embed: true } + ); + }); + // spot check a couple UI elements + cy.get("#fides-tab-Purposes"); + // Purposes + cy.getByTestId("toggle-Purposes").within(() => { + cy.get("input").should("be.checked"); + }); + // Vendors + cy.get("#fides-tab-Vendors").click(); + cy.getByTestId(`toggle-${SYSTEM_1.name}`).within(() => { + cy.get("input").should("be.checked"); + }); + }); }); describe("cmp api", () => { @@ -930,6 +1125,7 @@ describe("Fides-js TCF", () => { }); it("can handle inappropriate legint purposes", () => { + cy.getCookie(CONSENT_COOKIE_NAME).should("not.exist"); cy.fixture("consent/experience_tcf.json").then((payload) => { const experience: PrivacyExperience = payload.items[0]; // Set purpose with id 4 to LegInt which is not allowed! @@ -1507,6 +1703,141 @@ describe("Fides-js TCF", () => { }); }); + describe("fides string override options", () => { + it("uses TC string when set via cookie", () => { + cy.getCookie("fides_string").should("not.exist"); + // this TC string sets purpose 4 to false and purpose 7 to true + cy.setCookie( + "fides_string", + "CPzevcAPzevcAGXABBENATEIAAIAAAAAAAAAAAAAAAAA.IABE" + ); + cy.fixture("consent/experience_tcf.json").then((experience) => { + stubConfig({ + options: { + isOverlayEnabled: true, + tcfEnabled: true, + }, + experience: experience.items[0], + }); + }); + cy.window().then((win) => { + win.__tcfapi("addEventListener", 2, cy.stub().as("TCFEvent")); + }); + // Open the modal + cy.get("#fides-modal-link").click(); + + // verify CMP API + cy.get("@TCFEvent") + .its("lastCall.args") + .then(([tcData, success]) => { + expect(success).to.eql(true); + expect(tcData.eventStatus).to.eql("cmpuishown"); + expect(tcData.purpose.consents).to.eql({ + [PURPOSE_2.id]: false, + [PURPOSE_4.id]: false, + [PURPOSE_6.id]: false, + [PURPOSE_7.id]: true, + 1: false, + 2: false, + 3: false, + 5: false, + }); + expect(tcData.purpose.legitimateInterests).to.eql({}); + expect(tcData.vendor.consents).to.eql({}); + expect(tcData.vendor.legitimateInterests).to.eql({}); + }); + }); + it("uses TC string when set via query param", () => { + cy.getCookie("fides_string").should("not.exist"); + cy.fixture("consent/experience_tcf.json").then((experience) => { + stubConfig( + { + options: { + isOverlayEnabled: true, + tcfEnabled: true, + }, + experience: experience.items[0], + }, + null, + null, + // this TC string sets purpose 4 to false and purpose 7 to true + { fides_string: "CPzevcAPzevcAGXABBENATEIAAIAAAAAAAAAAAAAAAAA.IABE" } + ); + }); + cy.window().then((win) => { + win.__tcfapi("addEventListener", 2, cy.stub().as("TCFEvent")); + }); + // Open the modal + cy.get("#fides-modal-link").click(); + + // verify CMP API + cy.get("@TCFEvent") + .its("lastCall.args") + .then(([tcData, success]) => { + expect(success).to.eql(true); + expect(tcData.eventStatus).to.eql("cmpuishown"); + expect(tcData.purpose.consents).to.eql({ + [PURPOSE_2.id]: false, + [PURPOSE_4.id]: false, + [PURPOSE_6.id]: false, + [PURPOSE_7.id]: true, + 1: false, + 2: false, + 3: false, + 5: false, + }); + expect(tcData.purpose.legitimateInterests).to.eql({}); + expect(tcData.vendor.consents).to.eql({}); + expect(tcData.vendor.legitimateInterests).to.eql({}); + }); + }); + it("uses TC string when set via window obj", () => { + cy.getCookie("fides_string").should("not.exist"); + cy.fixture("consent/experience_tcf.json").then((experience) => { + stubConfig( + { + options: { + isOverlayEnabled: true, + tcfEnabled: true, + }, + experience: experience.items[0], + }, + null, + null, + null, + // this TC string sets purpose 4 to false and purpose 7 to true + { fides_string: "CPzevcAPzevcAGXABBENATEIAAIAAAAAAAAAAAAAAAAA.IABE" } + ); + }); + cy.window().then((win) => { + win.__tcfapi("addEventListener", 2, cy.stub().as("TCFEvent")); + }); + // Open the modal + cy.get("#fides-modal-link").click(); + + // verify CMP API + cy.get("@TCFEvent") + .its("lastCall.args") + .then(([tcData, success]) => { + expect(success).to.eql(true); + expect(tcData.eventStatus).to.eql("cmpuishown"); + expect(tcData.purpose.consents).to.eql({ + [PURPOSE_2.id]: false, + [PURPOSE_4.id]: false, + [PURPOSE_6.id]: false, + [PURPOSE_7.id]: true, + 1: false, + 2: false, + 3: false, + 5: false, + }); + expect(tcData.purpose.legitimateInterests).to.eql({}); + expect(tcData.vendor.consents).to.eql({}); + expect(tcData.vendor.legitimateInterests).to.eql({}); + }); + }); + }); + describe("ac string", () => { const AC_IDS = [42, 33, 49]; const acceptAllAcString = `1~${AC_IDS.sort().join(".")}`; diff --git a/clients/privacy-center/cypress/support/commands.ts b/clients/privacy-center/cypress/support/commands.ts index 184b811a49a..0f6b0f24339 100644 --- a/clients/privacy-center/cypress/support/commands.ts +++ b/clients/privacy-center/cypress/support/commands.ts @@ -5,6 +5,7 @@ import "cypress-wait-until"; import type { AppDispatch } from "~/app/store"; import type { FidesConfig } from "fides-js"; import type { PrivacyCenterClientSettings } from "~/app/server-environment"; +import VisitOptions = Cypress.VisitOptions; Cypress.Commands.add("getByTestId", (selector, ...args) => cy.get(`[data-testid='${selector}']`, ...args) @@ -55,31 +56,46 @@ Cypress.Commands.add("overrideSettings", (settings) => { ); }); -Cypress.Commands.add("visitConsentDemo", (options?: FidesConfig) => { - cy.visit("/fides-js-components-demo.html", { - onBeforeLoad: (win) => { - // eslint-disable-next-line no-param-reassign - win.fidesConfig = options; +Cypress.Commands.add( + "visitConsentDemo", + (options?: FidesConfig, queryParams?: any, windowParams?: any) => { + const visitOptions: Partial = { + onBeforeLoad: (win) => { + // eslint-disable-next-line no-param-reassign + win.fidesConfig = options; - // Add event listeners for Fides.js events - win.addEventListener( - "FidesInitialized", - cy.stub().as("FidesInitialized") - ); - win.addEventListener("FidesUpdated", cy.stub().as("FidesUpdated")); - win.addEventListener("FidesUIShown", cy.stub().as("FidesUIShown")); - win.addEventListener( - "FidesPreferenceToggled", - cy.stub().as("FidesPreferenceToggled") - ); + if (windowParams) { + // @ts-ignore + // eslint-disable-next-line no-param-reassign + win.config = { + fides: windowParams, + }; + } - // Add GTM stub - // eslint-disable-next-line no-param-reassign - win.dataLayer = []; - cy.stub(win.dataLayer, "push").as("dataLayerPush"); - }, - }); -}); + // Add event listeners for Fides.js events + win.addEventListener( + "FidesInitialized", + cy.stub().as("FidesInitialized") + ); + win.addEventListener("FidesUpdated", cy.stub().as("FidesUpdated")); + win.addEventListener("FidesUIShown", cy.stub().as("FidesUIShown")); + win.addEventListener( + "FidesPreferenceToggled", + cy.stub().as("FidesPreferenceToggled") + ); + + // Add GTM stub + // eslint-disable-next-line no-param-reassign + win.dataLayer = []; + cy.stub(win.dataLayer, "push").as("dataLayerPush"); + }, + }; + if (queryParams) { + visitOptions.qs = queryParams; + } + cy.visit("/fides-js-components-demo.html", visitOptions); + } +); declare global { namespace Cypress { @@ -161,9 +177,13 @@ declare global { ): Chainable; /** * Visit the /fides-js-components-demo page and inject config options - * @example cy.visitConsentDemo(fidesConfig); + * @example cy.visitConsentDemo(fidesConfig, {fidesEmbed: true}); */ - visitConsentDemo(options?: FidesConfig): Chainable; + visitConsentDemo( + options?: FidesConfig, + queryParams?: any, + windowParams?: any + ): Chainable; /** * Custom command to load a Privacy Center settings object into the app * diff --git a/clients/privacy-center/cypress/support/stubs.ts b/clients/privacy-center/cypress/support/stubs.ts index fdfd68f33a4..ff25e230b79 100644 --- a/clients/privacy-center/cypress/support/stubs.ts +++ b/clients/privacy-center/cypress/support/stubs.ts @@ -46,7 +46,9 @@ interface FidesConfigTesting { export const stubConfig = ( { consent, experience, geolocation, options }: Partial, mockGeolocationApiResp?: any, - mockExperienceApiResp?: any + mockExperienceApiResp?: any, + demoPageQueryParams?: any, + demoPageWindowParams?: any ) => { cy.fixture("consent/test_banner_options.json").then((config) => { const updatedConfig = { @@ -109,6 +111,10 @@ export const stubConfig = ( `${updatedConfig.options.fidesApiUrl}${FidesEndpointPaths.NOTICES_SERVED}`, { fixture: "consent/notices_served.json" } ).as("patchNoticesServed"); - cy.visitConsentDemo(updatedConfig); + cy.visitConsentDemo( + updatedConfig, + demoPageQueryParams, + demoPageWindowParams + ); }); };