From 4f437a13305acfb6b21600f8db1a914ed8820d15 Mon Sep 17 00:00:00 2001 From: Ming-jun Lu <40516784+mingjunlu@users.noreply.github.com> Date: Tue, 12 Mar 2024 18:55:01 +0800 Subject: [PATCH 1/3] fix(toolbar): fix an issue where x-ray didn't escape props content --- .../src/runtime/client/dev-toolbar/apps/xray.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/astro/src/runtime/client/dev-toolbar/apps/xray.ts b/packages/astro/src/runtime/client/dev-toolbar/apps/xray.ts index ae1910502d1d..893f6f6b46fb 100644 --- a/packages/astro/src/runtime/client/dev-toolbar/apps/xray.ts +++ b/packages/astro/src/runtime/client/dev-toolbar/apps/xray.ts @@ -1,3 +1,4 @@ +import { escape as escapeHTML } from 'html-escaper'; import type { DevToolbarApp, DevToolbarMetadata } from '../../../../@types/astro.js'; import type { DevToolbarHighlight } from '../ui-library/highlight.js'; import { @@ -137,13 +138,14 @@ export default { (prop: any) => !prop[0].startsWith('data-astro-cid-') ); if (islandPropsEntries.length > 0) { + const stringifiedProps = JSON.stringify( + Object.fromEntries(islandPropsEntries.map((prop: any) => [prop[0], prop[1][1]])), + undefined, + 2 + ); tooltip.sections.push({ title: 'Props', - content: `
${JSON.stringify(
- Object.fromEntries(islandPropsEntries.map((prop: any) => [prop[0], prop[1][1]])),
- undefined,
- 2
- )}
`,
+ content: `${escapeHTML(stringifiedProps)}
`,
});
}
From 428321eeb522444e71e4dfd4e63c2194e9dff4b8 Mon Sep 17 00:00:00 2001
From: Ming-jun Lu <40516784+mingjunlu@users.noreply.github.com>
Date: Tue, 12 Mar 2024 18:55:48 +0800
Subject: [PATCH 2/3] test(toolbar): add a test case related to x-ray
---
packages/astro/e2e/dev-toolbar.test.js | 28 +++++++++++++++++++
.../src/pages/xray-props-escape.astro | 9 ++++++
2 files changed, 37 insertions(+)
create mode 100644 packages/astro/e2e/fixtures/dev-toolbar/src/pages/xray-props-escape.astro
diff --git a/packages/astro/e2e/dev-toolbar.test.js b/packages/astro/e2e/dev-toolbar.test.js
index b30d2709819d..ac8d7b4dff59 100644
--- a/packages/astro/e2e/dev-toolbar.test.js
+++ b/packages/astro/e2e/dev-toolbar.test.js
@@ -100,6 +100,34 @@ test.describe('Dev Toolbar', () => {
await expect(xrayHighlightTooltip).not.toBeVisible();
});
+ test('xray escapes props content', async ({ page, astro }) => {
+ let isAlertCalled = false;
+ page.on('dialog', async (dialog) => {
+ isAlertCalled = true;
+ await dialog.accept();
+ });
+
+ await page.goto(astro.resolveUrl('/xray-props-escape'));
+
+ const toolbar = page.locator('astro-dev-toolbar');
+ const appButton = toolbar.locator('button[data-app-id="astro:xray"]');
+ await appButton.click();
+
+ const xrayCanvas = toolbar.locator('astro-dev-toolbar-app-canvas[data-app-id="astro:xray"]');
+ const xrayHighlight = xrayCanvas.locator('astro-dev-toolbar-highlight');
+ await expect(xrayHighlight).toBeVisible();
+
+ await xrayHighlight.hover();
+ const xrayHighlightTooltip = xrayHighlight.locator('astro-dev-toolbar-tooltip');
+ await expect(xrayHighlightTooltip).toBeVisible();
+
+ const code = xrayHighlightTooltip.locator('pre > code');
+ await expect(code).toHaveText(
+ JSON.stringify({ name: `` }, undefined, 2)
+ );
+ expect(isAlertCalled).toBe(false);
+ });
+
test('xray shows no islands message when there are none', async ({ page, astro }) => {
await page.goto(astro.resolveUrl('/xray-no-islands'));
diff --git a/packages/astro/e2e/fixtures/dev-toolbar/src/pages/xray-props-escape.astro b/packages/astro/e2e/fixtures/dev-toolbar/src/pages/xray-props-escape.astro
new file mode 100644
index 000000000000..f2e5049dc4ef
--- /dev/null
+++ b/packages/astro/e2e/fixtures/dev-toolbar/src/pages/xray-props-escape.astro
@@ -0,0 +1,9 @@
+---
+import { HelloWorld } from '../components/HelloWorld';
+---
+
+