You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by ru...@apache.org on 2026/06/05 23:48:40 UTC

(superset) 01/01: test(handlebars): E2E validation that formatDate helper renders a date (#32960)

This is an automated email from the ASF dual-hosted git repository.

rusackas pushed a commit to branch tdd/issue-32960-handlebars-formatdate
in repository https://gitbox.apache.org/repos/asf/superset.git

commit 51555ab4717b647699fb6f0cb7c6ee238418b544
Author: Claude Code <no...@anthropic.com>
AuthorDate: Fri Jun 5 16:48:09 2026 -0700

    test(handlebars): E2E validation that formatDate helper renders a date (#32960)
    
    Regression test for #32960: the `formatDate` Handlebars helper started
    rendering "i is not a function" (minified) / "moment is not a function" (dev)
    after 4.1.2. The helper (from just-handlebars-helpers) resolves moment lazily,
    which the bundled HandlebarsViewer no longer satisfies after switching to dayjs.
    
    This Playwright spec creates a Handlebars chart using
    `{{formatDate 'DD.MM.YYYY' ds}}` and asserts it renders a real formatted date
    instead of the helper error. It fails red on master, faithfully reproducing
    the bug, and turns green once the helper works again.
    
    Closes #32960
    
    Co-Authored-By: Claude Opus 4.8 <no...@anthropic.com>
---
 .../tests/chart/handlebars-format-date.spec.ts     | 103 +++++++++++++++++++++
 1 file changed, 103 insertions(+)

diff --git a/superset-frontend/playwright/tests/chart/handlebars-format-date.spec.ts b/superset-frontend/playwright/tests/chart/handlebars-format-date.spec.ts
new file mode 100644
index 00000000000..c52abbfbb04
--- /dev/null
+++ b/superset-frontend/playwright/tests/chart/handlebars-format-date.spec.ts
@@ -0,0 +1,103 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/**
+ * Regression for #32960: the `formatDate` Handlebars helper (provided by
+ * just-handlebars-helpers) stopped working after 4.1.2, rendering
+ * "i is not a function" (minified) / "moment is not a function" (dev) instead
+ * of the formatted date. The helper resolves `moment` lazily via
+ * `global.moment` / `require('moment/min/moment-with-locales')`, which the
+ * bundled HandlebarsViewer no longer satisfies (it switched to dayjs).
+ *
+ * This is a TDD validation test. It creates a Handlebars chart whose template
+ * uses `{{formatDate 'DD.MM.YYYY' ds}}` and asserts the chart renders a real
+ * formatted date rather than the helper error.
+ *
+ * CI green => formatDate works again; merging closes #32960.
+ * CI red   => the bug is still live; the fix belongs in the Handlebars plugin
+ *             (superset-frontend/plugins/plugin-chart-handlebars), e.g. by
+ *             providing a moment-free formatDate or making moment resolvable.
+ */
+import { testWithAssets, expect } from '../../helpers/fixtures';
+import { apiPost } from '../../helpers/api/requests';
+
+const DATASET_NAME = 'birth_names';
+
+async function findDatasetIdByName(page: any, name: string): Promise<number> {
+  const query = `(filters:!((col:table_name,opr:eq,value:'${name}')))`;
+  const resp = await page.request.get(`api/v1/dataset/?q=${query}`);
+  const body = await resp.json();
+  if (!body.result?.length) {
+    throw new Error(`Dataset ${name} not found`);
+  }
+  return body.result[0].id;
+}
+
+testWithAssets(
+  'Handlebars formatDate helper renders a formatted date (#32960)',
+  async ({ page, testAssets }) => {
+    const datasetId = await findDatasetIdByName(page, DATASET_NAME);
+
+    const params = {
+      datasource: `${datasetId}__table`,
+      viz_type: 'handlebars',
+      query_mode: 'aggregate',
+      groupby: ['ds'],
+      metrics: ['count'],
+      adhoc_filters: [],
+      row_limit: 5,
+      handlebarsTemplate:
+        "<ul class='data-list'>{{#each data}}" +
+        "<li class='hb-item'>{{formatDate 'DD.MM.YYYY' ds}}</li>" +
+        '{{/each}}</ul>',
+      styleTemplate: '',
+    };
+
+    const chartResp = await apiPost(page, 'api/v1/chart/', {
+      slice_name: `handlebars_format_date_${Date.now()}`,
+      viz_type: 'handlebars',
+      datasource_id: datasetId,
+      datasource_type: 'table',
+      params: JSON.stringify(params),
+    });
+    expect(chartResp.ok()).toBe(true);
+    const chartId: number = (await chartResp.json()).id;
+    testAssets.trackChart(chartId);
+
+    await page.goto(`explore/?slice_id=${chartId}`);
+    await page.waitForSelector('[data-test="datasource-control"]', {
+      timeout: 30_000,
+    });
+
+    const panel = page.locator('[data-test="chart-container"]');
+    await panel.waitFor({ state: 'visible', timeout: 30_000 });
+
+    // The helper error surfaces as a "... is not a function" message rendered
+    // in place of the chart content.
+    await expect(panel).not.toContainText('is not a function', {
+      timeout: 20_000,
+    });
+
+    // At least one list item should contain a DD.MM.YYYY formatted date.
+    await expect(panel.locator('li.hb-item').first()).toHaveText(
+      /\d{2}\.\d{2}\.\d{4}/,
+      { timeout: 20_000 },
+    );
+  },
+);