From 1f270c6a26c07c277c82516f563f0374481f0492 Mon Sep 17 00:00:00 2001 From: Maximilian Franzke Date: Tue, 11 Nov 2025 18:24:56 +0100 Subject: [PATCH 01/16] docs: adapted solution --- .../angular-showcase/src/app/components/form/form.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/showcases/angular-showcase/src/app/components/form/form.component.ts b/showcases/angular-showcase/src/app/components/form/form.component.ts index bfaca1fce4d1..d62371bf00ce 100644 --- a/showcases/angular-showcase/src/app/components/form/form.component.ts +++ b/showcases/angular-showcase/src/app/components/form/form.component.ts @@ -111,7 +111,7 @@ export class FormComponent { this.model.checkbox2 = false; this.form.get('input')?.setValue('reset'); this.form.get('textarea')?.setValue('reset'); - this.form.get('dateinput')?.setValue('reset'); + this.form.get('dateinput')?.setValue(''); this.form.get('checkbox')?.setValue(false); } From fc4cdc1dc7f94bf3def6f29fba8625d252ac3784 Mon Sep 17 00:00:00 2001 From: Maximilian Franzke Date: Tue, 11 Nov 2025 18:25:15 +0100 Subject: [PATCH 02/16] fix(input[type="date"]): resetting a field by the empty string --- packages/components/scripts/post-build/components.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/scripts/post-build/components.ts b/packages/components/scripts/post-build/components.ts index 9177fff99b1d..ae1dea9fe8ec 100644 --- a/packages/components/scripts/post-build/components.ts +++ b/packages/components/scripts/post-build/components.ts @@ -368,7 +368,7 @@ export const getComponents = (): Component[] => [ from: 'writeValue(value: any) {', to: 'writeValue(value: any) {\n' + - 'if (!value && (this.type() === "date" ||\n' + + 'if (!value && value !== "" && (this.type() === "date" ||\n' + ' this.type() === "time" ||\n' + ' this.type() === "week" ||\n' + ' this.type() === "month" ||\n' + From db1ffc34bf8d846a1af5a38154c8297269f7a8dd Mon Sep 17 00:00:00 2001 From: Maximilian Franzke <787658+mfranzke@users.noreply.github.com> Date: Tue, 11 Nov 2025 18:31:50 +0100 Subject: [PATCH 03/16] Create orange-eyes-pump.md --- .changeset/orange-eyes-pump.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/orange-eyes-pump.md diff --git a/.changeset/orange-eyes-pump.md b/.changeset/orange-eyes-pump.md new file mode 100644 index 000000000000..f80b66623a33 --- /dev/null +++ b/.changeset/orange-eyes-pump.md @@ -0,0 +1,5 @@ +--- +"@db-ux/ngx-core-components": patch +--- + +DBInput: inserting an empty string doesn't reset/empty date form fields From a7129d0ceba835630bdfd521efd64766a3d58a94 Mon Sep 17 00:00:00 2001 From: Maximilian Franzke <787658+mfranzke@users.noreply.github.com> Date: Tue, 11 Nov 2025 18:35:40 +0100 Subject: [PATCH 04/16] Clarify behavior of DBInput with empty string input --- .changeset/orange-eyes-pump.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/orange-eyes-pump.md b/.changeset/orange-eyes-pump.md index f80b66623a33..56b05abcb789 100644 --- a/.changeset/orange-eyes-pump.md +++ b/.changeset/orange-eyes-pump.md @@ -2,4 +2,4 @@ "@db-ux/ngx-core-components": patch --- -DBInput: inserting an empty string doesn't reset/empty date form fields +DBInput: inserting an empty string doesn't reset/empty date or time related form fields From 78e080bc3e72da3c36936aac591f14743d4f9fb1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 11 Nov 2025 17:36:17 +0000 Subject: [PATCH 05/16] Initial plan From 6a08b67a095b8e3bd25d3f9f7dc3c787bab3c63c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" Date: Tue, 11 Nov 2025 17:46:04 +0000 Subject: [PATCH 06/16] test: add test for date input clearing with empty string Co-authored-by: mfranzke <787658+mfranzke@users.noreply.github.com> --- .../blob-report/report-chromium-a211965.zip | Bin 0 -> 2292 bytes .../src/components/input/input.spec.tsx | 30 ++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 output/react/blob-report/report-chromium-a211965.zip diff --git a/output/react/blob-report/report-chromium-a211965.zip b/output/react/blob-report/report-chromium-a211965.zip new file mode 100644 index 0000000000000000000000000000000000000000..4f418bf373ae937f63d90206468b2b88d022b172 GIT binary patch literal 2292 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 O06G8w0Hg>20000*yhS|# literal 0 HcmV?d00001 diff --git a/packages/components/src/components/input/input.spec.tsx b/packages/components/src/components/input/input.spec.tsx index 92b18ff851fe..cde31c287faf 100644 --- a/packages/components/src/components/input/input.spec.tsx +++ b/packages/components/src/components/input/input.spec.tsx @@ -76,6 +76,36 @@ const testAction = () => { await expect(input).not.toHaveAttribute('enterkeyhint'); await expect(input).not.toHaveAttribute('inputmode'); }); + + test('should clear date input when value is set to empty string', async ({ + mount, + page + }) => { + const component = await mount( + + ); + const input = page.locator('input[type="date"]'); + + // Verify initial value is set + await expect(input).toHaveValue('2025-01-15'); + + // Update component with empty string value + await component.evaluate((node: any, newValue: string) => { + const inputElement = node.querySelector('input'); + if (inputElement) { + inputElement.value = newValue; + inputElement.dispatchEvent( + new Event('input', { bubbles: true }) + ); + inputElement.dispatchEvent( + new Event('change', { bubbles: true }) + ); + } + }, ''); + + // Verify the input is cleared + await expect(input).toHaveValue(''); + }); }; test.describe('DBInput', () => { From 0346ecdc4bff11d8f26e504ea1e942e3643891ee Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" Date: Tue, 11 Nov 2025 17:46:44 +0000 Subject: [PATCH 07/16] chore: add blob-report to .gitignore and remove test artifact Co-authored-by: mfranzke <787658+mfranzke@users.noreply.github.com> --- .gitignore | 1 + .../blob-report/report-chromium-a211965.zip | Bin 2292 -> 0 bytes 2 files changed, 1 insertion(+) delete mode 100644 output/react/blob-report/report-chromium-a211965.zip diff --git a/.gitignore b/.gitignore index e7d0292811a6..27f36cbc3f4b 100644 --- a/.gitignore +++ b/.gitignore @@ -76,3 +76,4 @@ showcases/patternhub/public/iframe-resizer/* /packages/agent-cli/test/.amazonq/rules/db-ux.md /core-web.iml /build-storybooks/ +blob-report/ diff --git a/output/react/blob-report/report-chromium-a211965.zip b/output/react/blob-report/report-chromium-a211965.zip deleted file mode 100644 index 4f418bf373ae937f63d90206468b2b88d022b172..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2292 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 O06G8w0Hg>20000*yhS|# From 798739515fbae422d5f8b610e98dc5cace06e22b Mon Sep 17 00:00:00 2001 From: Maximilian Franzke <787658+mfranzke@users.noreply.github.com> Date: Wed, 12 Nov 2025 15:15:05 +0100 Subject: [PATCH 08/16] Refactor writeValue condition for clarity --- packages/components/scripts/post-build/components.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/scripts/post-build/components.ts b/packages/components/scripts/post-build/components.ts index ae1dea9fe8ec..9177fff99b1d 100644 --- a/packages/components/scripts/post-build/components.ts +++ b/packages/components/scripts/post-build/components.ts @@ -368,7 +368,7 @@ export const getComponents = (): Component[] => [ from: 'writeValue(value: any) {', to: 'writeValue(value: any) {\n' + - 'if (!value && value !== "" && (this.type() === "date" ||\n' + + 'if (!value && (this.type() === "date" ||\n' + ' this.type() === "time" ||\n' + ' this.type() === "week" ||\n' + ' this.type() === "month" ||\n' + From 21b4a25a0a293474c652ecaf7f732774cfeac1fa Mon Sep 17 00:00:00 2001 From: Maximilian Franzke <787658+mfranzke@users.noreply.github.com> Date: Wed, 12 Nov 2025 15:41:05 +0100 Subject: [PATCH 09/16] Fix condition in writeValue method for value checks --- packages/components/scripts/post-build/components.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/scripts/post-build/components.ts b/packages/components/scripts/post-build/components.ts index 9177fff99b1d..ae1dea9fe8ec 100644 --- a/packages/components/scripts/post-build/components.ts +++ b/packages/components/scripts/post-build/components.ts @@ -368,7 +368,7 @@ export const getComponents = (): Component[] => [ from: 'writeValue(value: any) {', to: 'writeValue(value: any) {\n' + - 'if (!value && (this.type() === "date" ||\n' + + 'if (!value && value !== "" && (this.type() === "date" ||\n' + ' this.type() === "time" ||\n' + ' this.type() === "week" ||\n' + ' this.type() === "month" ||\n' + From 11603683bb51235aea61d39d5e79e79e71ce46ae Mon Sep 17 00:00:00 2001 From: Maximilian Franzke Date: Wed, 12 Nov 2025 15:56:29 +0100 Subject: [PATCH 10/16] test: another try --- .../src/components/input/input.spec.tsx | 131 ++++++++++++++---- 1 file changed, 106 insertions(+), 25 deletions(-) diff --git a/packages/components/src/components/input/input.spec.tsx b/packages/components/src/components/input/input.spec.tsx index cde31c287faf..d636bad5e328 100644 --- a/packages/components/src/components/input/input.spec.tsx +++ b/packages/components/src/components/input/input.spec.tsx @@ -77,34 +77,115 @@ const testAction = () => { await expect(input).not.toHaveAttribute('inputmode'); }); - test('should clear date input when value is set to empty string', async ({ - mount, + test('should handle empty string value for date input without clearing', async ({ page }) => { - const component = await mount( - + await page.goto(getPathname('components-input--default')); + + // Get the date input + const input = page.locator('db-input[type="date"] input'); + + // Set an initial date value + await input.fill('2024-01-15'); + await expect(input).toHaveValue('2024-01-15'); + + // Now set an empty string - this should NOT clear the input to null + await input.evaluate((el: HTMLInputElement) => { + el.value = ''; + }); + + // The value should be empty string, not null + const valueAfterEmpty = await input.evaluate( + (el: HTMLInputElement) => el.value + ); + expect(valueAfterEmpty).toBe(''); + + // Now test programmatically setting empty string via the component + const dbInput = page.locator('db-input[type="date"]'); + await dbInput.evaluate((el: any) => { + el.value = ''; + }); + + // Check that the internal input value is empty string, not cleared + const internalValue = await input.evaluate( + (el: HTMLInputElement) => el.value ); - const input = page.locator('input[type="date"]'); - - // Verify initial value is set - await expect(input).toHaveValue('2025-01-15'); - - // Update component with empty string value - await component.evaluate((node: any, newValue: string) => { - const inputElement = node.querySelector('input'); - if (inputElement) { - inputElement.value = newValue; - inputElement.dispatchEvent( - new Event('input', { bubbles: true }) - ); - inputElement.dispatchEvent( - new Event('change', { bubbles: true }) - ); - } - }, ''); - - // Verify the input is cleared - await expect(input).toHaveValue(''); + expect(internalValue).toBe(''); + + // Verify the component's value property + const componentValue = await dbInput.evaluate((el: any) => el.value); + expect(componentValue).toBe(''); + }); + + test('should distinguish between undefined, null, and empty string for date input', async ({ + page + }) => { + await page.goto(getPathname('components-input--default')); + + const dbInput = page.locator('db-input[type="date"]'); + const input = page.locator('db-input[type="date"] input'); + + // Set a date first + await dbInput.evaluate((el: any) => { + el.value = '2024-01-15'; + }); + await expect(input).toHaveValue('2024-01-15'); + + // Test empty string - should keep the input but make it empty + await dbInput.evaluate((el: any) => { + el.value = ''; + }); + let value = await input.evaluate((el: HTMLInputElement) => el.value); + expect(value).toBe(''); + + // Set date again + await dbInput.evaluate((el: any) => { + el.value = '2024-02-20'; + }); + await expect(input).toHaveValue('2024-02-20'); + + // Test null - should clear the input + await dbInput.evaluate((el: any) => { + el.value = null; + }); + value = await input.evaluate((el: HTMLInputElement) => el.value); + expect(value).toBe(''); + + // Set date again + await dbInput.evaluate((el: any) => { + el.value = '2024-03-25'; + }); + await expect(input).toHaveValue('2024-03-25'); + + // Test undefined - should clear the input + await dbInput.evaluate((el: any) => { + el.value = undefined; + }); + value = await input.evaluate((el: HTMLInputElement) => el.value); + expect(value).toBe(''); + }); + + test('should handle empty string for datetime-local input', async ({ + page + }) => { + await page.goto(getPathname('components-input--default')); + + const dbInput = page.locator('db-input[type="datetime-local"]'); + const input = page.locator('db-input[type="datetime-local"] input'); + + // Set a datetime value + await dbInput.evaluate((el: any) => { + el.value = '2024-01-15T10:30'; + }); + await expect(input).toHaveValue('2024-01-15T10:30'); + + // Set empty string - should not be treated as falsy and cleared + await dbInput.evaluate((el: any) => { + el.value = ''; + }); + + const value = await input.evaluate((el: HTMLInputElement) => el.value); + expect(value).toBe(''); }); }; From 55a044cf5b582d3710d3daaae66ad470f88f9da2 Mon Sep 17 00:00:00 2001 From: Maximilian Franzke Date: Wed, 12 Nov 2025 15:57:47 +0100 Subject: [PATCH 11/16] refactor: we need to test for our component, not the native element --- packages/components/src/components/input/input.spec.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/components/src/components/input/input.spec.tsx b/packages/components/src/components/input/input.spec.tsx index d636bad5e328..99f064e62e14 100644 --- a/packages/components/src/components/input/input.spec.tsx +++ b/packages/components/src/components/input/input.spec.tsx @@ -83,7 +83,7 @@ const testAction = () => { await page.goto(getPathname('components-input--default')); // Get the date input - const input = page.locator('db-input[type="date"] input'); + const input = page.locator('db-input[type="date"]'); // Set an initial date value await input.fill('2024-01-15'); @@ -123,7 +123,7 @@ const testAction = () => { await page.goto(getPathname('components-input--default')); const dbInput = page.locator('db-input[type="date"]'); - const input = page.locator('db-input[type="date"] input'); + const input = page.locator('db-input[type="date"]'); // Set a date first await dbInput.evaluate((el: any) => { @@ -171,7 +171,7 @@ const testAction = () => { await page.goto(getPathname('components-input--default')); const dbInput = page.locator('db-input[type="datetime-local"]'); - const input = page.locator('db-input[type="datetime-local"] input'); + const input = page.locator('db-input[type="datetime-local"]'); // Set a datetime value await dbInput.evaluate((el: any) => { From 19d3fa7839f60b21bab6e0eb0a0478fb84e0fb3f Mon Sep 17 00:00:00 2001 From: Maximilian Franzke Date: Wed, 12 Nov 2025 16:15:24 +0100 Subject: [PATCH 12/16] refactor: another try --- .../src/components/input/input.spec.tsx | 65 +++++++------------ 1 file changed, 25 insertions(+), 40 deletions(-) diff --git a/packages/components/src/components/input/input.spec.tsx b/packages/components/src/components/input/input.spec.tsx index 99f064e62e14..664b15f8087a 100644 --- a/packages/components/src/components/input/input.spec.tsx +++ b/packages/components/src/components/input/input.spec.tsx @@ -78,87 +78,73 @@ const testAction = () => { }); test('should handle empty string value for date input without clearing', async ({ - page + mount }) => { - await page.goto(getPathname('components-input--default')); - - // Get the date input - const input = page.locator('db-input[type="date"]'); + const comp: any = ; + const component = await mount(comp); + const input = component.locator('input'); // Set an initial date value await input.fill('2024-01-15'); await expect(input).toHaveValue('2024-01-15'); - // Now set an empty string - this should NOT clear the input to null - await input.evaluate((el: HTMLInputElement) => { + // Now programmatically set empty string via the component + await component.evaluate((el: any) => { el.value = ''; }); - // The value should be empty string, not null - const valueAfterEmpty = await input.evaluate( - (el: HTMLInputElement) => el.value - ); - expect(valueAfterEmpty).toBe(''); - - // Now test programmatically setting empty string via the component - const dbInput = page.locator('db-input[type="date"]'); - await dbInput.evaluate((el: any) => { - el.value = ''; - }); - - // Check that the internal input value is empty string, not cleared + // The internal input value should be empty string, not null const internalValue = await input.evaluate( (el: HTMLInputElement) => el.value ); expect(internalValue).toBe(''); - // Verify the component's value property - const componentValue = await dbInput.evaluate((el: any) => el.value); + // Verify the component's value property is also empty string + const componentValue = await component.evaluate((el: any) => el.value); expect(componentValue).toBe(''); }); test('should distinguish between undefined, null, and empty string for date input', async ({ - page + mount }) => { - await page.goto(getPathname('components-input--default')); - - const dbInput = page.locator('db-input[type="date"]'); - const input = page.locator('db-input[type="date"]'); + const comp: any = ; + const component = await mount(comp); + const input = component.locator('input'); // Set a date first - await dbInput.evaluate((el: any) => { + await component.evaluate((el: any) => { el.value = '2024-01-15'; }); await expect(input).toHaveValue('2024-01-15'); // Test empty string - should keep the input but make it empty - await dbInput.evaluate((el: any) => { + await component.evaluate((el: any) => { el.value = ''; }); let value = await input.evaluate((el: HTMLInputElement) => el.value); expect(value).toBe(''); // Set date again - await dbInput.evaluate((el: any) => { + await component.evaluate((el: any) => { el.value = '2024-02-20'; }); await expect(input).toHaveValue('2024-02-20'); // Test null - should clear the input - await dbInput.evaluate((el: any) => { + await component.evaluate((el: any) => { el.value = null; }); value = await input.evaluate((el: HTMLInputElement) => el.value); expect(value).toBe(''); // Set date again - await dbInput.evaluate((el: any) => { + await component.evaluate((el: any) => { el.value = '2024-03-25'; }); await expect(input).toHaveValue('2024-03-25'); // Test undefined - should clear the input - await dbInput.evaluate((el: any) => { + await component.evaluate((el: any) => { el.value = undefined; }); value = await input.evaluate((el: HTMLInputElement) => el.value); @@ -166,21 +152,20 @@ const testAction = () => { }); test('should handle empty string for datetime-local input', async ({ - page + mount }) => { - await page.goto(getPathname('components-input--default')); - - const dbInput = page.locator('db-input[type="datetime-local"]'); - const input = page.locator('db-input[type="datetime-local"]'); + const comp: any = ; + const component = await mount(comp); + const input = component.locator('input'); // Set a datetime value - await dbInput.evaluate((el: any) => { + await component.evaluate((el: any) => { el.value = '2024-01-15T10:30'; }); await expect(input).toHaveValue('2024-01-15T10:30'); // Set empty string - should not be treated as falsy and cleared - await dbInput.evaluate((el: any) => { + await component.evaluate((el: any) => { el.value = ''; }); From e516c72e4ed5a537264325ec0c1dcca837713dab Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" Date: Mon, 17 Nov 2025 07:43:54 +0000 Subject: [PATCH 13/16] fix: correct date input tests to use proper component remounting Co-authored-by: mfranzke <787658+mfranzke@users.noreply.github.com> --- .../src/components/input/input.spec.tsx | 103 ++++++++---------- 1 file changed, 45 insertions(+), 58 deletions(-) diff --git a/packages/components/src/components/input/input.spec.tsx b/packages/components/src/components/input/input.spec.tsx index 664b15f8087a..384b1bdbbb64 100644 --- a/packages/components/src/components/input/input.spec.tsx +++ b/packages/components/src/components/input/input.spec.tsx @@ -80,73 +80,57 @@ const testAction = () => { test('should handle empty string value for date input without clearing', async ({ mount }) => { - const comp: any = ; - const component = await mount(comp); - const input = component.locator('input'); - - // Set an initial date value - await input.fill('2024-01-15'); + // Test with controlled value prop + let component = await mount( + + ); + let input = component.locator('input'); await expect(input).toHaveValue('2024-01-15'); - // Now programmatically set empty string via the component - await component.evaluate((el: any) => { - el.value = ''; - }); + // Remount with empty string value - should accept empty string + await component.unmount(); + component = await mount(); + input = component.locator('input'); // The internal input value should be empty string, not null const internalValue = await input.evaluate( (el: HTMLInputElement) => el.value ); expect(internalValue).toBe(''); - - // Verify the component's value property is also empty string - const componentValue = await component.evaluate((el: any) => el.value); - expect(componentValue).toBe(''); }); test('should distinguish between undefined, null, and empty string for date input', async ({ mount }) => { - const comp: any = ; - const component = await mount(comp); - const input = component.locator('input'); - - // Set a date first - await component.evaluate((el: any) => { - el.value = '2024-01-15'; - }); + // Test with initial date value + let component = await mount( + + ); + let input = component.locator('input'); await expect(input).toHaveValue('2024-01-15'); - // Test empty string - should keep the input but make it empty - await component.evaluate((el: any) => { - el.value = ''; - }); + // Test empty string - should accept empty string as valid value + await component.unmount(); + component = await mount(); + input = component.locator('input'); let value = await input.evaluate((el: HTMLInputElement) => el.value); expect(value).toBe(''); - // Set date again - await component.evaluate((el: any) => { - el.value = '2024-02-20'; - }); - await expect(input).toHaveValue('2024-02-20'); - - // Test null - should clear the input - await component.evaluate((el: any) => { - el.value = null; - }); + // Test null - should also result in empty value + await component.unmount(); + component = await mount( + + ); + input = component.locator('input'); value = await input.evaluate((el: HTMLInputElement) => el.value); expect(value).toBe(''); - // Set date again - await component.evaluate((el: any) => { - el.value = '2024-03-25'; - }); - await expect(input).toHaveValue('2024-03-25'); - - // Test undefined - should clear the input - await component.evaluate((el: any) => { - el.value = undefined; - }); + // Test undefined - should also result in empty value + await component.unmount(); + component = await mount( + + ); + input = component.locator('input'); value = await input.evaluate((el: HTMLInputElement) => el.value); expect(value).toBe(''); }); @@ -154,20 +138,23 @@ const testAction = () => { test('should handle empty string for datetime-local input', async ({ mount }) => { - const comp: any = ; - const component = await mount(comp); - const input = component.locator('input'); - - // Set a datetime value - await component.evaluate((el: any) => { - el.value = '2024-01-15T10:30'; - }); + // Test with initial datetime value + let component = await mount( + + ); + let input = component.locator('input'); await expect(input).toHaveValue('2024-01-15T10:30'); - // Set empty string - should not be treated as falsy and cleared - await component.evaluate((el: any) => { - el.value = ''; - }); + // Test empty string - should accept empty string as valid value + await component.unmount(); + component = await mount( + + ); + input = component.locator('input'); const value = await input.evaluate((el: HTMLInputElement) => el.value); expect(value).toBe(''); From e3e3663161d1f656698eb5e4587fe04d6ea767cd Mon Sep 17 00:00:00 2001 From: Maximilian Franzke <787658+mfranzke@users.noreply.github.com> Date: Mon, 17 Nov 2025 13:40:20 +0100 Subject: [PATCH 14/16] Apply suggestions from code review Co-authored-by: Michael Kraus --- .../src/components/input/input.spec.tsx | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/packages/components/src/components/input/input.spec.tsx b/packages/components/src/components/input/input.spec.tsx index 384b1bdbbb64..584e81a5cd7a 100644 --- a/packages/components/src/components/input/input.spec.tsx +++ b/packages/components/src/components/input/input.spec.tsx @@ -113,8 +113,7 @@ const testAction = () => { await component.unmount(); component = await mount(); input = component.locator('input'); - let value = await input.evaluate((el: HTMLInputElement) => el.value); - expect(value).toBe(''); + await expect(input).toHaveValue(''); // Test null - should also result in empty value await component.unmount(); @@ -122,8 +121,7 @@ const testAction = () => { ); input = component.locator('input'); - value = await input.evaluate((el: HTMLInputElement) => el.value); - expect(value).toBe(''); + await expect(input).toHaveValue(''); // Test undefined - should also result in empty value await component.unmount(); @@ -131,8 +129,7 @@ const testAction = () => { ); input = component.locator('input'); - value = await input.evaluate((el: HTMLInputElement) => el.value); - expect(value).toBe(''); + await expect(input).toHaveValue(''); }); test('should handle empty string for datetime-local input', async ({ @@ -156,11 +153,22 @@ const testAction = () => { ); input = component.locator('input'); - const value = await input.evaluate((el: HTMLInputElement) => el.value); - expect(value).toBe(''); + await expect(input).toHaveValue(''); }); }; +test('should handle null as empty for datetime-local input', async ({ mount }) => { + const component = await mount(); + const input = component.locator('input'); + await expect(input).toHaveValue(''); +}); + +test('should handle undefined as empty for datetime-local input', async ({ mount }) => { + const component = await mount(); + const input = component.locator('input'); + await expect(input).toHaveValue(''); +}); + test.describe('DBInput', () => { test.use({ viewport: DEFAULT_VIEWPORT }); testComponent(); From 5deff5f29290a3ab8bd402980b1a48d4bc873b05 Mon Sep 17 00:00:00 2001 From: Maximilian Franzke <787658+mfranzke@users.noreply.github.com> Date: Mon, 17 Nov 2025 17:12:57 +0100 Subject: [PATCH 15/16] refactor: provoke test failure --- packages/components/scripts/post-build/components.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/scripts/post-build/components.ts b/packages/components/scripts/post-build/components.ts index ae1dea9fe8ec..9177fff99b1d 100644 --- a/packages/components/scripts/post-build/components.ts +++ b/packages/components/scripts/post-build/components.ts @@ -368,7 +368,7 @@ export const getComponents = (): Component[] => [ from: 'writeValue(value: any) {', to: 'writeValue(value: any) {\n' + - 'if (!value && value !== "" && (this.type() === "date" ||\n' + + 'if (!value && (this.type() === "date" ||\n' + ' this.type() === "time" ||\n' + ' this.type() === "week" ||\n' + ' this.type() === "month" ||\n' + From 890529fd3672e3b1aeaf3349bcc79ed641d2affb Mon Sep 17 00:00:00 2001 From: Maximilian Franzke <787658+mfranzke@users.noreply.github.com> Date: Mon, 17 Nov 2025 20:20:00 +0100 Subject: [PATCH 16/16] Fix condition in writeValue method for date types --- packages/components/scripts/post-build/components.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/scripts/post-build/components.ts b/packages/components/scripts/post-build/components.ts index 9177fff99b1d..ae1dea9fe8ec 100644 --- a/packages/components/scripts/post-build/components.ts +++ b/packages/components/scripts/post-build/components.ts @@ -368,7 +368,7 @@ export const getComponents = (): Component[] => [ from: 'writeValue(value: any) {', to: 'writeValue(value: any) {\n' + - 'if (!value && (this.type() === "date" ||\n' + + 'if (!value && value !== "" && (this.type() === "date" ||\n' + ' this.type() === "time" ||\n' + ' this.type() === "week" ||\n' + ' this.type() === "month" ||\n' +