diff --git a/packages/toolpad-app/src/server/toolpadAppBuilder.ts b/packages/toolpad-app/src/server/toolpadAppBuilder.ts index 4f18b1cf8c4..589169f9667 100644 --- a/packages/toolpad-app/src/server/toolpadAppBuilder.ts +++ b/packages/toolpad-app/src/server/toolpadAppBuilder.ts @@ -79,7 +79,7 @@ export function postProcessHtml(html: string, { config, dom }: PostProcessHtmlPa )}] = ${serializedInitialState}`, ]; - return html.replaceAll(``, toolpadScripts.join('\n')); + return html.replace(``, () => toolpadScripts.join('\n')); } interface ToolpadVitePluginParams { diff --git a/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/JsExpressionEditor.tsx b/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/JsExpressionEditor.tsx index 27e5499c82a..943d53bc008 100644 --- a/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/JsExpressionEditor.tsx +++ b/packages/toolpad-app/src/toolpad/AppEditor/PageEditor/JsExpressionEditor.tsx @@ -84,7 +84,7 @@ export function JsExpressionEditor({ .map(([propKey, propValue]) => { return `${propKey}: ${propValue.replaceAll( /\bThisComponent\b/g, - `RootObject[${JSON.stringify(key)}]`, + () => `RootObject[${JSON.stringify(key)}]`, )}`; }) .join('\n')} diff --git a/packages/toolpad-utils/src/fs.spec.ts b/packages/toolpad-utils/src/fs.spec.ts new file mode 100644 index 00000000000..9a4d74b7854 --- /dev/null +++ b/packages/toolpad-utils/src/fs.spec.ts @@ -0,0 +1,60 @@ +import { describe, test, beforeEach, afterEach, expect } from '@jest/globals'; +import * as fs from 'fs/promises'; +import * as path from 'path'; +import { fileReplace, fileReplaceAll } from './fs'; + +describe('fileReplace', () => { + let testDir: string; + + beforeEach(async () => { + testDir = await fs.mkdtemp('test-dir'); + }); + + afterEach(async () => { + await fs.rm(testDir, { recursive: true, force: true }); + }); + + test('can replace parts of a file', async () => { + const filePath = path.resolve(testDir, './test.txt'); + await fs.writeFile(filePath, 'Hello World, Hello', { encoding: 'utf-8' }); + await fileReplace(filePath, 'Hello', 'Goodbye'); + const content = await fs.readFile(filePath, { encoding: 'utf-8' }); + expect(content).toEqual('Goodbye World, Hello'); + }); + + test('can replace with double dollar signs', async () => { + const filePath = path.resolve(testDir, './test.txt'); + await fs.writeFile(filePath, 'Hello World', { encoding: 'utf-8' }); + await fileReplace(filePath, 'Hello', '$$'); + const content = await fs.readFile(filePath, { encoding: 'utf-8' }); + expect(content).toEqual('$$ World'); + }); +}); + +describe('fileReplaceAll', () => { + let testDir: string; + + beforeEach(async () => { + testDir = await fs.mkdtemp('test-dir'); + }); + + afterEach(async () => { + await fs.rm(testDir, { recursive: true, force: true }); + }); + + test('can replace parts of a file', async () => { + const filePath = path.resolve(testDir, './test.txt'); + await fs.writeFile(filePath, 'Hello World, Hello', { encoding: 'utf-8' }); + await fileReplaceAll(filePath, 'Hello', 'Goodbye'); + const content = await fs.readFile(filePath, { encoding: 'utf-8' }); + expect(content).toEqual('Goodbye World, Goodbye'); + }); + + test('can replace with double dollar signs', async () => { + const filePath = path.resolve(testDir, './test.txt'); + await fs.writeFile(filePath, 'Hello World', { encoding: 'utf-8' }); + await fileReplaceAll(filePath, 'Hello', '$$'); + const content = await fs.readFile(filePath, { encoding: 'utf-8' }); + expect(content).toEqual('$$ World'); + }); +}); diff --git a/packages/toolpad-utils/src/fs.ts b/packages/toolpad-utils/src/fs.ts index a339566c3c4..772739e3207 100644 --- a/packages/toolpad-utils/src/fs.ts +++ b/packages/toolpad-utils/src/fs.ts @@ -89,7 +89,7 @@ export async function fileReplace( replaceValue: string, ): Promise { const queriesFileContent = await fs.readFile(filePath, { encoding: 'utf-8' }); - const updatedFileContent = queriesFileContent.replace(searchValue, replaceValue); + const updatedFileContent = queriesFileContent.replace(searchValue, () => replaceValue); await fs.writeFile(filePath, updatedFileContent); } @@ -99,6 +99,6 @@ export async function fileReplaceAll( replaceValue: string, ) { const queriesFileContent = await fs.readFile(filePath, { encoding: 'utf-8' }); - const updatedFileContent = queriesFileContent.replaceAll(searchValue, replaceValue); + const updatedFileContent = queriesFileContent.replaceAll(searchValue, () => replaceValue); await fs.writeFile(filePath, updatedFileContent); } diff --git a/test/integration/backend-basic/fixture/toolpad/pages/page/page.yml b/test/integration/backend-basic/fixture/toolpad/pages/page/page.yml new file mode 100644 index 00000000000..e9f9460766d --- /dev/null +++ b/test/integration/backend-basic/fixture/toolpad/pages/page/page.yml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: page +spec: + id: d9iAjrh + title: page + display: shell + content: + - component: PageRow + name: pageRow + children: + - component: Text + name: text + props: + value: $$ diff --git a/test/integration/backend-basic/index.spec.ts b/test/integration/backend-basic/index.spec.ts index 155a1fc672c..7483c5fe417 100644 --- a/test/integration/backend-basic/index.spec.ts +++ b/test/integration/backend-basic/index.spec.ts @@ -5,6 +5,8 @@ import { ToolpadRuntime } from '../../models/ToolpadRuntime'; import { ToolpadEditor } from '../../models/ToolpadEditor'; import { waitForMatch } from '../../utils/streams'; +const BASIC_TESTS_PAGE_ID = '5q1xd0t'; + test.use({ ignoreConsoleErrors: [ // Chrome: @@ -49,7 +51,7 @@ test('functions basics', async ({ page }) => { test('function editor reload', async ({ page, localApp }) => { const editorModel = new ToolpadEditor(page); - await editorModel.goto(); + await editorModel.goToPageById(BASIC_TESTS_PAGE_ID); await expect(editorModel.appCanvas.getByText('edited hello')).toBeVisible(); @@ -61,7 +63,7 @@ test('function editor reload', async ({ page, localApp }) => { test('function editor parameters update', async ({ page, localApp }) => { const editorModel = new ToolpadEditor(page); - await editorModel.goto(); + await editorModel.goToPageById(BASIC_TESTS_PAGE_ID); await editorModel.componentEditor.getByRole('button', { name: 'withParams' }).click(); diff --git a/test/integration/bindings/fixture/toolpad/pages/charset/page.yml b/test/integration/bindings/fixture/toolpad/pages/encoding/page.yml similarity index 68% rename from test/integration/bindings/fixture/toolpad/pages/charset/page.yml rename to test/integration/bindings/fixture/toolpad/pages/encoding/page.yml index 3a2a33f7c40..3811222e4dd 100644 --- a/test/integration/bindings/fixture/toolpad/pages/charset/page.yml +++ b/test/integration/bindings/fixture/toolpad/pages/encoding/page.yml @@ -2,7 +2,7 @@ apiVersion: v1 kind: page spec: id: lWm2sZu - title: charset + title: Encoding display: shell content: - component: PageRow @@ -14,3 +14,7 @@ spec: value: $$jsExpression: | `Can pass utf-8: "€"` + - component: Text + name: text + props: + value: 'Can pass double dollars: "$$"' diff --git a/test/integration/bindings/index.spec.ts b/test/integration/bindings/index.spec.ts index 78593cd8bfe..1bea36c622b 100644 --- a/test/integration/bindings/index.spec.ts +++ b/test/integration/bindings/index.spec.ts @@ -31,10 +31,13 @@ test('bindings', async ({ page }) => { await expect(page.getByText('-test2-')).toBeVisible(); }); -test('charset', async ({ page }) => { +test('encoding', async ({ page }) => { const runtimeModel = new ToolpadRuntime(page); - await runtimeModel.gotoPage('charset'); + await runtimeModel.gotoPage('encoding'); const test1 = page.getByText('Can pass utf-8: "€"'); await expect(test1).toBeVisible(); + + const test2 = page.getByText('Can pass double dollars: "$$"'); + await expect(test2).toBeVisible(); });