From e53f7c0b6fd5298ef9b002eb136c94190922af6d Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 17 Mar 2026 23:51:47 +0000 Subject: [PATCH 1/2] fix(influxdb3): backfill missing product URLs in localStorage Returning visitors with stale localStorage (created before core/enterprise products were added) had undefined URL values for new products. The updateUrls() function then replaced Hugo-rendered hostnames like localhost:8181 with the string "undefined" in api-endpoint blocks. Fix by merging DEFAULT_STORAGE_URLS as fallbacks when reading from localStorage, so new product keys are always present. closes #6960 https://claude.ai/code/session_01GJZ2yMR5DBk1feqTD5LeHW --- assets/js/services/local-storage.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/assets/js/services/local-storage.js b/assets/js/services/local-storage.js index 8efccde126..22b778733a 100644 --- a/assets/js/services/local-storage.js +++ b/assets/js/services/local-storage.js @@ -117,7 +117,10 @@ function getInfluxDBUrls() { initializeStorageItem('urls', JSON.stringify(DEFAULT_STORAGE_URLS)); } - return JSON.parse(localStorage.getItem(urlStorageKey)); + const storedUrls = JSON.parse(localStorage.getItem(urlStorageKey)); + // Backfill any new default keys missing from stored data (e.g., when new + // products like core/enterprise are added after a user's first visit). + return { ...DEFAULT_STORAGE_URLS, ...storedUrls }; } // Get the current or previous URL for a specific product or a custom url @@ -131,8 +134,8 @@ function getInfluxDBUrl(product) { const urlsString = localStorage.getItem(urlStorageKey); const urlsObj = JSON.parse(urlsString); - // Return the URL of the specified product - return urlsObj[product]; + // Return the URL of the specified product, falling back to the default + return urlsObj[product] ?? DEFAULT_STORAGE_URLS[product]; } /* From 81475aa140e095b3c4d316fce36c590d9e173039 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 18 Mar 2026 13:44:12 +0000 Subject: [PATCH 2/2] test(influxdb3): add Cypress tests for localStorage URL backfill Adds 2 E2E tests for the fix in #6960: 1. Stale localStorage (missing `core` key) should not cause "undefined" to appear in api-endpoint or code blocks on the plugins page. 2. Fresh localStorage should be initialized with all expected product URL keys (oss, cloud, core, enterprise, serverless, dedicated, clustered). Run with: node cypress/support/run-e2e-specs.js --spec "cypress/e2e/influxdb-url.cy.js" --no-mapping https://claude.ai/code/session_01GJZ2yMR5DBk1feqTD5LeHW --- cypress/e2e/influxdb-url.cy.js | 80 ++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 cypress/e2e/influxdb-url.cy.js diff --git a/cypress/e2e/influxdb-url.cy.js b/cypress/e2e/influxdb-url.cy.js new file mode 100644 index 0000000000..7203e69d8b --- /dev/null +++ b/cypress/e2e/influxdb-url.cy.js @@ -0,0 +1,80 @@ +/// + +/** + * InfluxDB URL localStorage E2E Test Suite + * + * Tests that the InfluxDB URL replacement logic in influxdb-url.js handles + * localStorage correctly, including stale data from returning visitors. + * + * Regression tests for https://github.com/influxdata/docs-v2/issues/6960 + * where stale localStorage missing the `core` key caused JavaScript to + * replace rendered hostnames with "undefined" in code blocks. + */ + +const STORAGE_KEY = 'influxdata_docs_urls'; +const TEST_PAGE = '/influxdb3/core/plugins/'; +const EXPECTED_PRODUCT_KEYS = [ + 'oss', + 'cloud', + 'core', + 'enterprise', + 'serverless', + 'dedicated', + 'clustered', +]; + +describe('InfluxDB URL - localStorage', function () { + it('should not render "undefined" in code blocks when localStorage is missing product keys', function () { + // Simulate a returning visitor whose localStorage was created before + // core/enterprise products were added — missing those keys entirely. + const staleUrls = { + oss: 'http://localhost:8086', + cloud: 'https://us-west-2-1.aws.cloud2.influxdata.com', + prev_oss: 'http://localhost:8086', + prev_cloud: 'https://us-west-2-1.aws.cloud2.influxdata.com', + custom: '', + }; + + cy.visit(TEST_PAGE, { + onBeforeLoad(win) { + win.localStorage.setItem(STORAGE_KEY, JSON.stringify(staleUrls)); + }, + }); + + // The api-endpoint block should show the default Core host, not "undefined" + cy.get('.article--content pre.api-endpoint') + .first() + .should('contain', 'localhost:8181') + .and('not.contain', 'undefined'); + + // No code block in the article should contain "undefined" as a bare host + cy.get('.article--content pre:not(.preserve)').each(($el) => { + cy.wrap($el).invoke('text').should('not.match', /undefined\/api\//); + }); + }); + + it('should backfill all expected product URL keys into localStorage', function () { + cy.visit(TEST_PAGE, { + onBeforeLoad(win) { + // Start with no stored URLs — forces initialization + win.localStorage.removeItem(STORAGE_KEY); + }, + }); + + // After the page loads and JS initializes, localStorage should contain + // all expected product keys with non-empty URL values. + cy.window().then((win) => { + const stored = JSON.parse(win.localStorage.getItem(STORAGE_KEY)); + expect(stored).to.be.an('object'); + + EXPECTED_PRODUCT_KEYS.forEach((key) => { + expect(stored, `stored URLs should have key "${key}"`).to.have.property( + key + ); + expect(stored[key], `"${key}" should be a non-empty string`).to.be.a( + 'string' + ).and.not.be.empty; + }); + }); + }); +});