diff --git a/packages/pluggableWidgets/barcode-generator-web/src/__tests__/BarcodeGenerator.spec.tsx b/packages/pluggableWidgets/barcode-generator-web/src/__tests__/BarcodeGenerator.spec.tsx
index 01b4ef0c56..97fda1610d 100644
--- a/packages/pluggableWidgets/barcode-generator-web/src/__tests__/BarcodeGenerator.spec.tsx
+++ b/packages/pluggableWidgets/barcode-generator-web/src/__tests__/BarcodeGenerator.spec.tsx
@@ -60,8 +60,8 @@ const createBarcodeProps = (
lastChar: "",
enableMod43: false,
allowDownload: false,
- downloadButtonCaption: dynamic("Download"),
- downloadButtonAriaLabel: dynamic("Download barcode"),
+ downloadButtonCaption: dynamic.available("Download"),
+ downloadButtonAriaLabel: dynamic.available("Download barcode"),
displayValue: false,
showAsCard: false,
codeWidth: 2,
@@ -69,10 +69,10 @@ const createBarcodeProps = (
codeMargin: 4,
qrSize: 128,
qrMargin: 2,
- qrTitle: dynamic(""),
+ qrTitle: dynamic.available(""),
qrLevel: "L",
qrOverlay: false,
- qrOverlaySrc: dynamic(createMockWebImage()),
+ qrOverlaySrc: dynamic.available(createMockWebImage()),
qrOverlayCenter: true,
qrOverlayX: 0,
qrOverlayY: 0,
@@ -81,10 +81,10 @@ const createBarcodeProps = (
qrOverlayOpacity: new Big(1),
qrOverlayExcavate: true,
addonFormat: "None",
- addonValue: dynamic(),
+ addonValue: dynamic.unavailable(),
addonSpacing: 20,
buttonPosition: "bottom",
- codeValue: dynamic("test-barcode-value"),
+ codeValue: dynamic.available("test-barcode-value"),
logLevel: "Info",
showTitle: false,
...overrides
@@ -99,7 +99,7 @@ describe("BarcodeGenerator", () => {
describe("core rendering", () => {
it("renders QR code when codeValue is available", () => {
const props = createBarcodeProps({
- codeValue: dynamic("Hello World")
+ codeValue: dynamic.available("Hello World")
});
render();
@@ -111,7 +111,7 @@ describe("BarcodeGenerator", () => {
it("shows fallback message when codeValue is loading", () => {
const props = createBarcodeProps({
- codeValue: dynamic("", true)
+ codeValue: dynamic.loading("")
});
render();
@@ -122,7 +122,7 @@ describe("BarcodeGenerator", () => {
it("shows fallback message when codeValue is unavailable", () => {
const props = createBarcodeProps({
- codeValue: dynamic()
+ codeValue: dynamic.unavailable()
});
render();
@@ -135,7 +135,7 @@ describe("BarcodeGenerator", () => {
const props = createBarcodeProps({
class: "custom-class",
tabIndex: 2,
- codeValue: dynamic("test")
+ codeValue: dynamic.available("test")
});
const { container } = render();
@@ -148,7 +148,7 @@ describe("BarcodeGenerator", () => {
it("applies card styling when showAsCard is true", () => {
const props = createBarcodeProps({
showAsCard: true,
- codeValue: dynamic("test")
+ codeValue: dynamic.available("test")
});
const { container } = render();
@@ -163,7 +163,7 @@ describe("BarcodeGenerator", () => {
it("renders CODE128 barcode correctly", () => {
const props = createBarcodeProps({
codeFormat: "CODE128" as CodeFormatEnum,
- codeValue: dynamic("123456789")
+ codeValue: dynamic.available("123456789")
});
render();
@@ -179,7 +179,7 @@ describe("BarcodeGenerator", () => {
const props = createBarcodeProps({
codeFormat: "Custom" as CodeFormatEnum,
customCodeFormat: "CODE39" as CustomCodeFormatEnum,
- codeValue: dynamic("ABC-123")
+ codeValue: dynamic.available("ABC-123")
});
render();
@@ -195,7 +195,7 @@ describe("BarcodeGenerator", () => {
const props = createBarcodeProps({
codeFormat: "Custom" as CodeFormatEnum,
customCodeFormat: "CODE93" as CustomCodeFormatEnum,
- codeValue: dynamic("CODE93VALUE")
+ codeValue: dynamic.available("CODE93VALUE")
});
render();
@@ -211,7 +211,7 @@ describe("BarcodeGenerator", () => {
const props = createBarcodeProps({
codeFormat: "Custom" as CodeFormatEnum,
customCodeFormat: "EAN13" as CustomCodeFormatEnum,
- codeValue: dynamic("1234567890128")
+ codeValue: dynamic.available("1234567890128")
});
render();
@@ -227,7 +227,7 @@ describe("BarcodeGenerator", () => {
const props = createBarcodeProps({
codeFormat: "Custom" as CodeFormatEnum,
customCodeFormat: "EAN8" as CustomCodeFormatEnum,
- codeValue: dynamic("12345678")
+ codeValue: dynamic.available("12345678")
});
render();
@@ -243,7 +243,7 @@ describe("BarcodeGenerator", () => {
const props = createBarcodeProps({
codeFormat: "Custom" as CodeFormatEnum,
customCodeFormat: "UPC" as CustomCodeFormatEnum,
- codeValue: dynamic("123456789012")
+ codeValue: dynamic.available("123456789012")
});
render();
@@ -259,7 +259,7 @@ describe("BarcodeGenerator", () => {
const props = createBarcodeProps({
codeFormat: "Custom" as CodeFormatEnum,
customCodeFormat: "ITF14" as CustomCodeFormatEnum,
- codeValue: dynamic("12345678901234")
+ codeValue: dynamic.available("12345678901234")
});
render();
@@ -275,7 +275,7 @@ describe("BarcodeGenerator", () => {
const props = createBarcodeProps({
codeFormat: "Custom" as CodeFormatEnum,
customCodeFormat: "MSI" as CustomCodeFormatEnum,
- codeValue: dynamic("123456")
+ codeValue: dynamic.available("123456")
});
render();
@@ -291,7 +291,7 @@ describe("BarcodeGenerator", () => {
const props = createBarcodeProps({
codeFormat: "Custom" as CodeFormatEnum,
customCodeFormat: "pharmacode" as CustomCodeFormatEnum,
- codeValue: dynamic("1234567")
+ codeValue: dynamic.available("1234567")
});
render();
@@ -307,7 +307,7 @@ describe("BarcodeGenerator", () => {
const props = createBarcodeProps({
codeFormat: "Custom" as CodeFormatEnum,
customCodeFormat: "codabar" as CustomCodeFormatEnum,
- codeValue: dynamic("123-456")
+ codeValue: dynamic.available("123-456")
});
render();
@@ -325,7 +325,7 @@ describe("BarcodeGenerator", () => {
it("renders QR code with custom size", () => {
const props = createBarcodeProps({
qrSize: 256,
- codeValue: dynamic("Custom Size QR")
+ codeValue: dynamic.available("Custom Size QR")
});
render();
@@ -336,7 +336,7 @@ describe("BarcodeGenerator", () => {
it("renders QR code with custom margin", () => {
const props = createBarcodeProps({
qrMargin: 5,
- codeValue: dynamic("test")
+ codeValue: dynamic.available("test")
});
render();
@@ -350,7 +350,7 @@ describe("BarcodeGenerator", () => {
levels.forEach(level => {
const props = createBarcodeProps({
qrLevel: level,
- codeValue: dynamic("test")
+ codeValue: dynamic.available("test")
});
const { unmount } = render();
@@ -362,9 +362,9 @@ describe("BarcodeGenerator", () => {
it("renders QR code with title", () => {
const props = createBarcodeProps({
- qrTitle: dynamic("QR Code Title"),
+ qrTitle: dynamic.available("QR Code Title"),
showTitle: true,
- codeValue: dynamic("test")
+ codeValue: dynamic.available("test")
});
render();
@@ -378,9 +378,9 @@ describe("BarcodeGenerator", () => {
it("renders QR code with image overlay when qrOverlay is true", () => {
const props = createBarcodeProps({
qrOverlay: true,
- qrOverlaySrc: dynamic(createMockWebImage()),
+ qrOverlaySrc: dynamic.available(createMockWebImage()),
qrOverlayCenter: true,
- codeValue: dynamic("test")
+ codeValue: dynamic.available("test")
});
render();
@@ -391,11 +391,11 @@ describe("BarcodeGenerator", () => {
it("renders QR code with centered image overlay", () => {
const props = createBarcodeProps({
qrOverlay: true,
- qrOverlaySrc: dynamic(createMockWebImage()),
+ qrOverlaySrc: dynamic.available(createMockWebImage()),
qrOverlayCenter: true,
qrOverlayX: 10,
qrOverlayY: 20,
- codeValue: dynamic("test")
+ codeValue: dynamic.available("test")
});
render();
@@ -406,11 +406,11 @@ describe("BarcodeGenerator", () => {
it("renders QR code with positioned image overlay", () => {
const props = createBarcodeProps({
qrOverlay: true,
- qrOverlaySrc: dynamic(createMockWebImage()),
+ qrOverlaySrc: dynamic.available(createMockWebImage()),
qrOverlayCenter: false,
qrOverlayX: 10,
qrOverlayY: 20,
- codeValue: dynamic("test")
+ codeValue: dynamic.available("test")
});
render();
@@ -421,10 +421,10 @@ describe("BarcodeGenerator", () => {
it("renders QR code with image overlay custom dimensions", () => {
const props = createBarcodeProps({
qrOverlay: true,
- qrOverlaySrc: dynamic(createMockWebImage()),
+ qrOverlaySrc: dynamic.available(createMockWebImage()),
qrOverlayWidth: 50,
qrOverlayHeight: 50,
- codeValue: dynamic("test")
+ codeValue: dynamic.available("test")
});
render();
@@ -435,9 +435,9 @@ describe("BarcodeGenerator", () => {
it("renders QR code with image overlay opacity", () => {
const props = createBarcodeProps({
qrOverlay: true,
- qrOverlaySrc: dynamic(createMockWebImage()),
+ qrOverlaySrc: dynamic.available(createMockWebImage()),
qrOverlayOpacity: Big(0.75),
- codeValue: dynamic("test")
+ codeValue: dynamic.available("test")
});
render();
@@ -448,9 +448,9 @@ describe("BarcodeGenerator", () => {
it("renders QR code with image excavation enabled", () => {
const props = createBarcodeProps({
qrOverlay: true,
- qrOverlaySrc: dynamic(createMockWebImage()),
+ qrOverlaySrc: dynamic.available(createMockWebImage()),
qrOverlayExcavate: true,
- codeValue: dynamic("test")
+ codeValue: dynamic.available("test")
});
render();
@@ -461,8 +461,8 @@ describe("BarcodeGenerator", () => {
it("does not render image overlay when qrOverlaySrc is unavailable", () => {
const props = createBarcodeProps({
qrOverlay: true,
- qrOverlaySrc: dynamic(),
- codeValue: dynamic("test")
+ qrOverlaySrc: dynamic.unavailable(),
+ codeValue: dynamic.available("test")
});
render();
@@ -477,7 +477,7 @@ describe("BarcodeGenerator", () => {
it("does not render download button when allowDownload is false", () => {
const props = createBarcodeProps({
allowDownload: false,
- codeValue: dynamic("test")
+ codeValue: dynamic.available("test")
});
render();
@@ -488,8 +488,8 @@ describe("BarcodeGenerator", () => {
it("renders download button with custom caption", () => {
const props = createBarcodeProps({
allowDownload: true,
- downloadButtonCaption: dynamic("Export Code"),
- codeValue: dynamic("test")
+ downloadButtonCaption: dynamic.available("Export Code"),
+ codeValue: dynamic.available("test")
});
render();
@@ -500,9 +500,9 @@ describe("BarcodeGenerator", () => {
it("renders download button with correct aria-label for QR code", () => {
const props = createBarcodeProps({
allowDownload: true,
- downloadButtonAriaLabel: dynamic("Download QR code"),
+ downloadButtonAriaLabel: dynamic.available("Download QR code"),
codeFormat: "QRCode" as CodeFormatEnum,
- codeValue: dynamic("test")
+ codeValue: dynamic.available("test")
});
render();
@@ -514,8 +514,8 @@ describe("BarcodeGenerator", () => {
const props = createBarcodeProps({
allowDownload: true,
buttonPosition: "top" as const,
- downloadButtonCaption: dynamic("Download"),
- codeValue: dynamic("test")
+ downloadButtonCaption: dynamic.available("Download"),
+ codeValue: dynamic.available("test")
});
const { container } = render();
@@ -533,8 +533,8 @@ describe("BarcodeGenerator", () => {
const props = createBarcodeProps({
allowDownload: true,
buttonPosition: "bottom" as const,
- downloadButtonCaption: dynamic("Download"),
- codeValue: dynamic("test")
+ downloadButtonCaption: dynamic.available("Download"),
+ codeValue: dynamic.available("test")
});
render();
@@ -548,9 +548,9 @@ describe("BarcodeGenerator", () => {
const props = createBarcodeProps({
allowDownload: true,
- downloadButtonCaption: dynamic("Download"),
+ downloadButtonCaption: dynamic.available("Download"),
codeFormat: "QRCode" as CodeFormatEnum,
- codeValue: dynamic("test")
+ codeValue: dynamic.available("test")
});
render();
@@ -564,8 +564,8 @@ describe("BarcodeGenerator", () => {
it("renders download button with icon and caption", () => {
const props = createBarcodeProps({
allowDownload: true,
- downloadButtonCaption: dynamic("Save"),
- codeValue: dynamic("test")
+ downloadButtonCaption: dynamic.available("Save"),
+ codeValue: dynamic.available("test")
});
render();
@@ -581,7 +581,7 @@ describe("BarcodeGenerator", () => {
const props = createBarcodeProps({
codeFormat: "CODE128" as CodeFormatEnum,
displayValue: true,
- codeValue: dynamic("DISPLAY123")
+ codeValue: dynamic.available("DISPLAY123")
});
render();
@@ -597,7 +597,7 @@ describe("BarcodeGenerator", () => {
const props = createBarcodeProps({
codeFormat: "CODE128" as CodeFormatEnum,
displayValue: false,
- codeValue: dynamic("NODISPLAY")
+ codeValue: dynamic.available("NODISPLAY")
});
render();
@@ -613,7 +613,7 @@ describe("BarcodeGenerator", () => {
const props = createBarcodeProps({
codeFormat: "CODE128" as CodeFormatEnum,
codeWidth: 3,
- codeValue: dynamic("WIDTH_TEST")
+ codeValue: dynamic.available("WIDTH_TEST")
});
render();
@@ -629,7 +629,7 @@ describe("BarcodeGenerator", () => {
const props = createBarcodeProps({
codeFormat: "CODE128" as CodeFormatEnum,
codeHeight: 300,
- codeValue: dynamic("HEIGHT_TEST")
+ codeValue: dynamic.available("HEIGHT_TEST")
});
render();
@@ -645,7 +645,7 @@ describe("BarcodeGenerator", () => {
const props = createBarcodeProps({
codeFormat: "CODE128" as CodeFormatEnum,
codeMargin: 8,
- codeValue: dynamic("MARGIN_TEST")
+ codeValue: dynamic.available("MARGIN_TEST")
});
render();
@@ -664,7 +664,7 @@ describe("BarcodeGenerator", () => {
const props = createBarcodeProps({
codeFormat: "CODE128" as CodeFormatEnum,
enableEan128: true,
- codeValue: dynamic("EAN128TEST")
+ codeValue: dynamic.available("EAN128TEST")
});
render();
@@ -680,7 +680,7 @@ describe("BarcodeGenerator", () => {
const props = createBarcodeProps({
codeFormat: "CODE128" as CodeFormatEnum,
enableFlat: true,
- codeValue: dynamic("FLATTEST")
+ codeValue: dynamic.available("FLATTEST")
});
render();
@@ -696,7 +696,7 @@ describe("BarcodeGenerator", () => {
const props = createBarcodeProps({
codeFormat: "CODE128" as CodeFormatEnum,
enableMod43: true,
- codeValue: dynamic("MOD43TEST")
+ codeValue: dynamic.available("MOD43TEST")
});
render();
@@ -712,7 +712,7 @@ describe("BarcodeGenerator", () => {
const props = createBarcodeProps({
codeFormat: "CODE128" as CodeFormatEnum,
lastChar: "X",
- codeValue: dynamic("LASTCHARTEST")
+ codeValue: dynamic.available("LASTCHARTEST")
});
render();
@@ -740,10 +740,10 @@ describe("BarcodeGenerator", () => {
const props = createBarcodeProps({
codeFormat: "Custom" as CodeFormatEnum,
customCodeFormat: "EAN13" as CustomCodeFormatEnum,
- addonValue: dynamic("12345"),
+ addonValue: dynamic.available("12345"),
addonFormat: "EAN5",
addonSpacing: 25,
- codeValue: dynamic("1234567890128")
+ codeValue: dynamic.available("1234567890128")
});
render();
@@ -768,9 +768,9 @@ describe("BarcodeGenerator", () => {
const props = createBarcodeProps({
codeFormat: "Custom" as CodeFormatEnum,
customCodeFormat: "EAN13" as CustomCodeFormatEnum,
- addonValue: dynamic("12"),
+ addonValue: dynamic.available("12"),
addonFormat: "EAN2",
- codeValue: dynamic("1234567890128")
+ codeValue: dynamic.available("1234567890128")
});
render();
@@ -784,9 +784,9 @@ describe("BarcodeGenerator", () => {
const props = createBarcodeProps({
codeFormat: "Custom" as CodeFormatEnum,
customCodeFormat: "EAN13" as CustomCodeFormatEnum,
- addonValue: dynamic("12345"),
+ addonValue: dynamic.available("12345"),
addonFormat: "None",
- codeValue: dynamic("1234567890128")
+ codeValue: dynamic.available("1234567890128")
});
render();
@@ -807,10 +807,10 @@ describe("BarcodeGenerator", () => {
const props = createBarcodeProps({
codeFormat: "Custom" as CodeFormatEnum,
customCodeFormat: "EAN13" as CustomCodeFormatEnum,
- addonValue: dynamic("12345"),
+ addonValue: dynamic.available("12345"),
addonFormat: "EAN5",
addonSpacing: 40,
- codeValue: dynamic("1234567890128")
+ codeValue: dynamic.available("1234567890128")
});
render();
@@ -828,7 +828,7 @@ describe("BarcodeGenerator", () => {
const props = createBarcodeProps({
codeFormat: "CODE128" as CodeFormatEnum,
- codeValue: dynamic("INVALID")
+ codeValue: dynamic.available("INVALID")
});
render();
@@ -844,7 +844,7 @@ describe("BarcodeGenerator", () => {
const props = createBarcodeProps({
codeFormat: "CODE128" as CodeFormatEnum,
- codeValue: dynamic("TEST")
+ codeValue: dynamic.available("TEST")
});
render();
@@ -861,7 +861,7 @@ describe("BarcodeGenerator", () => {
const props = createBarcodeProps({
codeFormat: "CODE128" as CodeFormatEnum,
- codeValue: dynamic("BAD")
+ codeValue: dynamic.available("BAD")
});
const { unmount } = render();
@@ -876,7 +876,7 @@ describe("BarcodeGenerator", () => {
const goodProps = createBarcodeProps({
codeFormat: "CODE128" as CodeFormatEnum,
- codeValue: dynamic("GOOD")
+ codeValue: dynamic.available("GOOD")
});
render();
@@ -889,9 +889,9 @@ describe("BarcodeGenerator", () => {
describe("accessibility", () => {
it("renders QR code title as semantic element when provided", () => {
const props = createBarcodeProps({
- qrTitle: dynamic("Invoice QR Code"),
+ qrTitle: dynamic.available("Invoice QR Code"),
showTitle: true,
- codeValue: dynamic("test")
+ codeValue: dynamic.available("test")
});
render();
@@ -903,9 +903,9 @@ describe("BarcodeGenerator", () => {
it("does not render title when showTitle is false", () => {
const props = createBarcodeProps({
- qrTitle: dynamic("title"),
+ qrTitle: dynamic.available("title"),
showTitle: false,
- codeValue: dynamic("test")
+ codeValue: dynamic.available("test")
});
render();
@@ -916,9 +916,9 @@ describe("BarcodeGenerator", () => {
it("download button has proper semantics", () => {
const props = createBarcodeProps({
allowDownload: true,
- downloadButtonCaption: dynamic("Download Barcode"),
- downloadButtonAriaLabel: dynamic("Download current barcode as PNG"),
- codeValue: dynamic("test")
+ downloadButtonCaption: dynamic.available("Download Barcode"),
+ downloadButtonAriaLabel: dynamic.available("Download current barcode as PNG"),
+ codeValue: dynamic.available("test")
});
render();
@@ -933,8 +933,8 @@ describe("BarcodeGenerator", () => {
const props = createBarcodeProps({
allowDownload: true,
- downloadButtonCaption: dynamic("Download"),
- codeValue: dynamic("test")
+ downloadButtonCaption: dynamic.available("Download"),
+ codeValue: dynamic.available("test")
});
render();
@@ -954,7 +954,7 @@ describe("BarcodeGenerator", () => {
const props = createBarcodeProps({
codeFormat: "CODE128" as CodeFormatEnum,
- codeValue: dynamic("TEST")
+ codeValue: dynamic.available("TEST")
});
render();
@@ -965,7 +965,7 @@ describe("BarcodeGenerator", () => {
it("barcode widget container is focusable when tabIndex is set", () => {
const props = createBarcodeProps({
tabIndex: 0,
- codeValue: dynamic("test")
+ codeValue: dynamic.available("test")
});
const { container } = render();
@@ -980,12 +980,12 @@ describe("BarcodeGenerator", () => {
it("renders QR code with download, title, and image overlay", () => {
const props = createBarcodeProps({
allowDownload: true,
- qrTitle: dynamic("Secure QR"),
+ qrTitle: dynamic.available("Secure QR"),
showTitle: true,
qrOverlay: true,
- qrOverlaySrc: dynamic(createMockWebImage()),
- downloadButtonCaption: dynamic("Save QR"),
- codeValue: dynamic("secure-data")
+ qrOverlaySrc: dynamic.available(createMockWebImage()),
+ downloadButtonCaption: dynamic.available("Save QR"),
+ codeValue: dynamic.available("secure-data")
});
render();
@@ -1009,12 +1009,12 @@ describe("BarcodeGenerator", () => {
enableFlat: true,
enableMod43: true,
allowDownload: true,
- downloadButtonCaption: dynamic("Export"),
+ downloadButtonCaption: dynamic.available("Export"),
codeWidth: 3,
codeHeight: 250,
codeMargin: 5,
lastChar: "Z",
- codeValue: dynamic("FULL_TEST")
+ codeValue: dynamic.available("FULL_TEST")
});
render();
diff --git a/packages/pluggableWidgets/calendar-web/src/__tests__/Calendar.spec.tsx b/packages/pluggableWidgets/calendar-web/src/__tests__/Calendar.spec.tsx
index 6174878704..e31691c5cf 100644
--- a/packages/pluggableWidgets/calendar-web/src/__tests__/Calendar.spec.tsx
+++ b/packages/pluggableWidgets/calendar-web/src/__tests__/Calendar.spec.tsx
@@ -72,8 +72,8 @@ const customViewProps: CalendarContainerProps = {
view: "custom",
defaultViewStandard: "month",
defaultViewCustom: "work_week",
- editable: dynamic(true),
- showEventDate: dynamic(true),
+ editable: dynamic.available(true),
+ showEventDate: dynamic.available(true),
widthUnit: "percentage",
width: 100,
heightUnit: "pixels",
diff --git a/packages/pluggableWidgets/checkbox-radio-selection-web/src/CheckboxRadioSelection.editorPreview.tsx b/packages/pluggableWidgets/checkbox-radio-selection-web/src/CheckboxRadioSelection.editorPreview.tsx
index 27cea5406b..a85e59e263 100644
--- a/packages/pluggableWidgets/checkbox-radio-selection-web/src/CheckboxRadioSelection.editorPreview.tsx
+++ b/packages/pluggableWidgets/checkbox-radio-selection-web/src/CheckboxRadioSelection.editorPreview.tsx
@@ -1,18 +1,24 @@
-import { generateUUID } from "@mendix/widget-plugin-platform/framework/generate-uuid";
+import type { DynamicValue } from "mendix";
import { ReactElement, useMemo } from "react";
+import { generateUUID } from "@mendix/widget-plugin-platform/framework/generate-uuid";
import { CheckboxRadioSelectionPreviewProps } from "../typings/CheckboxRadioSelectionProps";
+import { CheckboxSelection } from "./components/CheckboxSelection/CheckboxSelection";
import { RadioSelection } from "./components/RadioSelection/RadioSelection";
-import { dynamic } from "@mendix/widget-plugin-test-utils";
-import { MultiSelector, SelectionBaseProps, SingleSelector } from "./helpers/types";
-import { StaticPreviewSelector } from "./helpers/Static/Preview/StaticPreviewSelector";
+import { AssociationPreviewSelector } from "./helpers/Association/Preview/AssociationPreviewSelector";
import {
DatabaseMultiPreviewSelector,
DatabasePreviewSelector
} from "./helpers/Database/Preview/DatabasePreviewSelector";
-import { AssociationPreviewSelector } from "./helpers/Association/Preview/AssociationPreviewSelector";
+import { StaticPreviewSelector } from "./helpers/Static/Preview/StaticPreviewSelector";
+import { MultiSelector, SelectionBaseProps, SingleSelector } from "./helpers/types";
import "./ui/CheckboxRadioSelection.scss";
import "./ui/CheckboxRadioSelectionPreview.scss";
-import { CheckboxSelection } from "./components/CheckboxSelection/CheckboxSelection";
+
+const available = (value: T): DynamicValue =>
+ ({
+ status: "available",
+ value
+ }) as DynamicValue;
export const preview = (props: CheckboxRadioSelectionPreviewProps): ReactElement => {
const id = generateUUID().toString();
@@ -21,9 +27,9 @@ export const preview = (props: CheckboxRadioSelectionPreviewProps): ReactElement
inputId: id,
labelId: `${id}-label`,
readOnlyStyle: props.readOnlyStyle,
- ariaRequired: dynamic(false),
- ariaLabel: dynamic(""),
- groupName: dynamic(`${id}-group`),
+ ariaRequired: available(false),
+ ariaLabel: available(""),
+ groupName: available(`${id}-group`),
noOptionsText: "No options available"
};
diff --git a/packages/pluggableWidgets/combobox-web/AGENTS.md b/packages/pluggableWidgets/combobox-web/AGENTS.md
index 492e5e7b10..6166c7c4f8 100644
--- a/packages/pluggableWidgets/combobox-web/AGENTS.md
+++ b/packages/pluggableWidgets/combobox-web/AGENTS.md
@@ -297,7 +297,7 @@ Uses `@mendix/widget-plugin-test-utils` builders:
- `ReferenceValueBuilder` — mocks ReferenceValue (single association)
- `ReferenceSetValueBuilder` — mocks ReferenceSetValue (multi association)
- `ListValueBuilder` — mocks ListValue datasource with `.withItems()`, `.withHasMore()`
-- `dynamic(value?)` — wraps in DynamicValue
+- `dynamic.[available|loading|unavailable](value?)` — wraps in DynamicValue
- `obj(id?)` — creates mock ObjectItem
- `list(items)` — creates mock ListValue
- `setupIntersectionObserverStub()` — stubs browser IntersectionObserver
diff --git a/packages/pluggableWidgets/combobox-web/src/Combobox.editorPreview.tsx b/packages/pluggableWidgets/combobox-web/src/Combobox.editorPreview.tsx
index 43f931961f..289b9c1edc 100644
--- a/packages/pluggableWidgets/combobox-web/src/Combobox.editorPreview.tsx
+++ b/packages/pluggableWidgets/combobox-web/src/Combobox.editorPreview.tsx
@@ -1,13 +1,19 @@
-import { generateUUID } from "@mendix/widget-plugin-platform/framework/generate-uuid";
+import type { DynamicValue } from "mendix";
import { ReactElement, useMemo } from "react";
+import { generateUUID } from "@mendix/widget-plugin-platform/framework/generate-uuid";
import { ComboboxPreviewProps } from "../typings/ComboboxProps";
import { SingleSelection } from "./components/SingleSelection/SingleSelection";
-import { dynamic } from "@mendix/widget-plugin-test-utils";
-import { SelectionBaseProps, SingleSelector } from "./helpers/types";
import "./ui/Combobox.scss";
import { AssociationPreviewSelector } from "./helpers/Association/Preview/AssociationPreviewSelector";
-import { StaticPreviewSelector } from "./helpers/Static/Preview/StaticPreviewSelector";
import { DatabasePreviewSelector } from "./helpers/Database/Preview/DatabasePreviewSelector";
+import { StaticPreviewSelector } from "./helpers/Static/Preview/StaticPreviewSelector";
+import { SelectionBaseProps, SingleSelector } from "./helpers/types";
+
+const available = (value: T): DynamicValue =>
+ ({
+ status: "available",
+ value
+ }) as DynamicValue;
export const preview = (props: ComboboxPreviewProps): ReactElement => {
const id = generateUUID().toString();
@@ -16,7 +22,7 @@ export const preview = (props: ComboboxPreviewProps): ReactElement => {
inputId: id,
labelId: `${id}-label`,
readOnlyStyle: props.readOnlyStyle,
- ariaRequired: dynamic(false),
+ ariaRequired: available(false),
a11yConfig: {
ariaLabels: {
clearSelection: props.clearButtonAriaLabel,
diff --git a/packages/pluggableWidgets/combobox-web/src/__tests__/MultiSelection.spec.tsx b/packages/pluggableWidgets/combobox-web/src/__tests__/MultiSelection.spec.tsx
index d9c439bf98..a2d67ee5cf 100644
--- a/packages/pluggableWidgets/combobox-web/src/__tests__/MultiSelection.spec.tsx
+++ b/packages/pluggableWidgets/combobox-web/src/__tests__/MultiSelection.spec.tsx
@@ -40,23 +40,23 @@ describe("Combo box (Association)", () => {
optionsSourceAssociationCaptionExpression: listExpression(() => "$currentObject/CountryName"),
optionsSourceAssociationCustomContentType: "no",
optionsSourceAssociationCustomContent: undefined,
- emptyOptionText: dynamic("Select an option 111"),
- ariaRequired: dynamic(true),
+ emptyOptionText: dynamic.available("Select an option 111"),
+ ariaRequired: dynamic.available(true),
clearable: true,
filterType: "contains",
selectedItemsStyle: "text",
readOnlyStyle: "bordered",
lazyLoading: false,
loadingType: "spinner",
- noOptionsText: dynamic("no options found"),
- clearButtonAriaLabel: dynamic("Clear selection"),
- removeValueAriaLabel: dynamic("Remove value"),
+ noOptionsText: dynamic.available("no options found"),
+ clearButtonAriaLabel: dynamic.available("Clear selection"),
+ removeValueAriaLabel: dynamic.available("Remove value"),
selectAllButton: true, // Causes +1 option to be added to the menu
- selectAllButtonCaption: dynamic("Select All"),
+ selectAllButtonCaption: dynamic.available("Select All"),
selectionMethod: "checkbox",
- a11ySelectedValue: dynamic("Selected value:"),
- a11yOptionsAvailable: dynamic("Options available:"),
- a11yInstructions: dynamic("a11yInstructions"),
+ a11ySelectedValue: dynamic.available("Selected value:"),
+ a11yOptionsAvailable: dynamic.available("Options available:"),
+ a11yInstructions: dynamic.available("a11yInstructions"),
showFooter: false,
databaseAttributeString: new EditableValueBuilder().build(),
optionsSourceDatabaseCaptionType: "attribute",
@@ -65,23 +65,23 @@ describe("Combo box (Association)", () => {
staticAttribute: new EditableValueBuilder().build(),
optionsSourceStaticDataSource: [
{
- staticDataSourceValue: dynamic("value1"),
+ staticDataSourceValue: dynamic.available("value1"),
staticDataSourceCustomContent: undefined,
- staticDataSourceCaption: dynamic("caption1")
+ staticDataSourceCaption: dynamic.available("caption1")
},
{
- staticDataSourceValue: dynamic("value2"),
+ staticDataSourceValue: dynamic.available("value2"),
staticDataSourceCustomContent: undefined,
- staticDataSourceCaption: dynamic("caption2")
+ staticDataSourceCaption: dynamic.available("caption2")
}
],
selectedItemsSorting: "none",
customEditability: "default",
- customEditabilityExpression: dynamic(false),
+ customEditabilityExpression: dynamic.available(false),
filterInputDebounceInterval: 200
};
if (defaultProps.optionsSourceAssociationCaptionType === "expression") {
- defaultProps.optionsSourceAssociationCaptionExpression!.get = i => dynamic(`${i.id}`);
+ defaultProps.optionsSourceAssociationCaptionExpression!.get = i => dynamic.available(`${i.id}`);
}
});
diff --git a/packages/pluggableWidgets/combobox-web/src/__tests__/SingleSelection.spec.tsx b/packages/pluggableWidgets/combobox-web/src/__tests__/SingleSelection.spec.tsx
index 519961d022..f587113377 100644
--- a/packages/pluggableWidgets/combobox-web/src/__tests__/SingleSelection.spec.tsx
+++ b/packages/pluggableWidgets/combobox-web/src/__tests__/SingleSelection.spec.tsx
@@ -50,22 +50,22 @@ describe("Combo box (Association)", () => {
optionsSourceAssociationCaptionExpression: listExpression(() => "$currentObject/CountryName"),
optionsSourceAssociationCustomContentType: "no",
optionsSourceAssociationCustomContent: undefined,
- emptyOptionText: dynamic("Select an option 111"),
- ariaRequired: dynamic(true),
+ emptyOptionText: dynamic.available("Select an option 111"),
+ ariaRequired: dynamic.available(true),
clearable: true,
filterType: "contains",
selectedItemsStyle: "text",
readOnlyStyle: "bordered",
lazyLoading: false,
loadingType: "spinner",
- clearButtonAriaLabel: dynamic("Clear selection"),
- removeValueAriaLabel: dynamic("Remove value"),
- selectAllButtonCaption: dynamic("Select All"),
+ clearButtonAriaLabel: dynamic.available("Clear selection"),
+ removeValueAriaLabel: dynamic.available("Remove value"),
+ selectAllButtonCaption: dynamic.available("Select All"),
selectAllButton: false,
selectionMethod: "checkbox",
- a11ySelectedValue: dynamic("Selected value:"),
- a11yOptionsAvailable: dynamic("Options available:"),
- a11yInstructions: dynamic("a11yInstructions"),
+ a11ySelectedValue: dynamic.available("Selected value:"),
+ a11yOptionsAvailable: dynamic.available("Options available:"),
+ a11yInstructions: dynamic.available("a11yInstructions"),
showFooter: false,
databaseAttributeString: new EditableValueBuilder().build(),
optionsSourceDatabaseCaptionType: "attribute",
@@ -74,23 +74,23 @@ describe("Combo box (Association)", () => {
staticAttribute: new EditableValueBuilder().build(),
optionsSourceStaticDataSource: [
{
- staticDataSourceValue: dynamic("value1"),
+ staticDataSourceValue: dynamic.available("value1"),
staticDataSourceCustomContent: undefined,
- staticDataSourceCaption: dynamic("caption1")
+ staticDataSourceCaption: dynamic.available("caption1")
},
{
- staticDataSourceValue: dynamic("value2"),
+ staticDataSourceValue: dynamic.available("value2"),
staticDataSourceCustomContent: undefined,
- staticDataSourceCaption: dynamic("caption2")
+ staticDataSourceCaption: dynamic.available("caption2")
}
],
selectedItemsSorting: "none",
customEditability: "default",
- customEditabilityExpression: dynamic(false),
+ customEditabilityExpression: dynamic.available(false),
filterInputDebounceInterval: 200
};
if (defaultProps.optionsSourceAssociationCaptionType === "expression") {
- defaultProps.optionsSourceAssociationCaptionExpression!.get = i => dynamic(`${i.id}`);
+ defaultProps.optionsSourceAssociationCaptionExpression!.get = i => dynamic.available(`${i.id}`);
}
});
it("renders combobox widget", () => {
diff --git a/packages/pluggableWidgets/combobox-web/src/__tests__/StaticSelection.spec.tsx b/packages/pluggableWidgets/combobox-web/src/__tests__/StaticSelection.spec.tsx
index b9f28f6d85..cf9c8d6103 100644
--- a/packages/pluggableWidgets/combobox-web/src/__tests__/StaticSelection.spec.tsx
+++ b/packages/pluggableWidgets/combobox-web/src/__tests__/StaticSelection.spec.tsx
@@ -50,22 +50,22 @@ describe("Combo box (Static values)", () => {
optionsSourceAssociationCaptionExpression: listExpression(() => "$currentObject/CountryName"),
optionsSourceAssociationCustomContentType: "no",
optionsSourceAssociationCustomContent: undefined,
- emptyOptionText: dynamic("Select an option 111"),
- ariaRequired: dynamic(true),
+ emptyOptionText: dynamic.available("Select an option 111"),
+ ariaRequired: dynamic.available(true),
clearable: true,
filterType: "contains",
selectedItemsStyle: "text",
readOnlyStyle: "bordered",
lazyLoading: false,
loadingType: "spinner",
- clearButtonAriaLabel: dynamic("Clear selection"),
- removeValueAriaLabel: dynamic("Remove value"),
- selectAllButtonCaption: dynamic("Select All"),
+ clearButtonAriaLabel: dynamic.available("Clear selection"),
+ removeValueAriaLabel: dynamic.available("Remove value"),
+ selectAllButtonCaption: dynamic.available("Select All"),
selectAllButton: false,
selectionMethod: "checkbox",
- a11ySelectedValue: dynamic("Selected value:"),
- a11yOptionsAvailable: dynamic("Options available:"),
- a11yInstructions: dynamic("a11yInstructions"),
+ a11ySelectedValue: dynamic.available("Selected value:"),
+ a11yOptionsAvailable: dynamic.available("Options available:"),
+ a11yInstructions: dynamic.available("a11yInstructions"),
showFooter: false,
databaseAttributeString: new EditableValueBuilder().build(),
optionsSourceDatabaseCaptionType: "attribute",
@@ -74,23 +74,23 @@ describe("Combo box (Static values)", () => {
staticAttribute: new EditableValueBuilder().withValue("value1").build(),
optionsSourceStaticDataSource: [
{
- staticDataSourceValue: dynamic("value1"),
+ staticDataSourceValue: dynamic.available("value1"),
staticDataSourceCustomContent: undefined,
- staticDataSourceCaption: dynamic("caption1")
+ staticDataSourceCaption: dynamic.available("caption1")
},
{
- staticDataSourceValue: dynamic("value2"),
+ staticDataSourceValue: dynamic.available("value2"),
staticDataSourceCustomContent: undefined,
- staticDataSourceCaption: dynamic("caption2")
+ staticDataSourceCaption: dynamic.available("caption2")
}
],
selectedItemsSorting: "none",
customEditability: "default",
- customEditabilityExpression: dynamic(false),
+ customEditabilityExpression: dynamic.available(false),
filterInputDebounceInterval: 200
};
if (defaultProps.optionsSourceAssociationCaptionType === "expression") {
- defaultProps.optionsSourceAssociationCaptionExpression!.get = i => dynamic(`${i.id}`);
+ defaultProps.optionsSourceAssociationCaptionExpression!.get = i => dynamic.available(`${i.id}`);
}
});
it("renders combobox widget", () => {
diff --git a/packages/pluggableWidgets/combobox-web/src/helpers/Database/__tests__/DatabaseSingleSelectionSelector.spec.ts b/packages/pluggableWidgets/combobox-web/src/helpers/Database/__tests__/DatabaseSingleSelectionSelector.spec.ts
index 876c77aea4..41783d99f2 100644
--- a/packages/pluggableWidgets/combobox-web/src/helpers/Database/__tests__/DatabaseSingleSelectionSelector.spec.ts
+++ b/packages/pluggableWidgets/combobox-web/src/helpers/Database/__tests__/DatabaseSingleSelectionSelector.spec.ts
@@ -40,7 +40,7 @@ function buildProps({ items, values, targetValue, selection }: PropsOverrides):
optionsSourceDatabaseCaptionAttribute: captionAttr,
optionsSourceDatabaseValueAttribute: valueAttr,
databaseAttributeString: targetAttr as any,
- emptyOptionText: dynamic("Select..."),
+ emptyOptionText: dynamic.available("Select..."),
optionsSourceDatabaseCustomContentType: "no",
optionsSourceAssociationCustomContentType: "no",
staticDataSourceCustomContentType: "no",
@@ -50,14 +50,14 @@ function buildProps({ items, values, targetValue, selection }: PropsOverrides):
lazyLoading: false,
loadingType: "spinner",
customEditability: "default",
- customEditabilityExpression: dynamic(false),
+ customEditabilityExpression: dynamic.available(false),
filterInputDebounceInterval: 200,
selectedItemsStyle: "text",
readOnlyStyle: "bordered",
selectionMethod: "checkbox",
selectAllButton: false,
- selectAllButtonCaption: dynamic("Select All"),
- ariaRequired: dynamic(true),
+ selectAllButtonCaption: dynamic.available("Select All"),
+ ariaRequired: dynamic.available(true),
showFooter: false,
selectedItemsSorting: "none",
attributeEnumeration: new EditableValueBuilder().build(),
diff --git a/packages/pluggableWidgets/datagrid-date-filter-web/src/components/__tests__/DatagridDateFilter.spec.tsx b/packages/pluggableWidgets/datagrid-date-filter-web/src/components/__tests__/DatagridDateFilter.spec.tsx
index 0b309fff11..c858ba8c2f 100644
--- a/packages/pluggableWidgets/datagrid-date-filter-web/src/components/__tests__/DatagridDateFilter.spec.tsx
+++ b/packages/pluggableWidgets/datagrid-date-filter-web/src/components/__tests__/DatagridDateFilter.spec.tsx
@@ -3,7 +3,7 @@ import { DateInputFilterStore } from "@mendix/widget-plugin-filtering/stores/inp
import { ObservableFilterHost } from "@mendix/widget-plugin-filtering/typings/ObservableFilterHost";
import {
actionValue,
- dynamicValue,
+ dynamic,
EditableValueBuilder,
ListAttributeValueBuilder
} from "@mendix/widget-plugin-test-utils";
@@ -97,7 +97,7 @@ describe("Date Filter", () => {
{...commonProps}
onChange={action}
valueAttribute={attribute}
- placeholder={dynamicValue("Placeholder")}
+ placeholder={dynamic.available("Placeholder")}
/>
);
@@ -111,7 +111,7 @@ describe("Date Filter", () => {
it("initialize with defaultValue", async () => {
// 946684800000 = 01.01.2000
const date = new Date(946684800000);
- render((date)} />);
+ render();
expect(screen.getByRole("textbox")).toHaveValue("01/01/2000");
});
@@ -121,7 +121,7 @@ describe("Date Filter", () => {
const { rerender } = render();
expect(screen.getByRole("textbox")).toHaveValue("");
- rerender((date)} />);
+ rerender();
expect(screen.getByRole("textbox")).toHaveValue("");
});
@@ -129,7 +129,7 @@ describe("Date Filter", () => {
// 946684800000 = 01.01.2000
const date = new Date(946684800000);
const { rerender } = render(
- (date)} />
+
);
expect(screen.getByRole("textbox")).toHaveValue("01/01/2000");
@@ -271,7 +271,7 @@ describe("Date Filter", () => {
it("has correct short week days for en-US", async () => {
window.mx = createMXObjectMock("en_US", "en-US");
- render();
+ render();
const input = screen.getByRole("textbox");
await act(async () => {
@@ -283,7 +283,7 @@ describe("Date Filter", () => {
it("has correct short week days for en-US and starts week at Monday", async () => {
window.mx = createMXObjectMock("en_US", "en-US", 1);
- render();
+ render();
const input = screen.getByRole("textbox");
await act(async () => {
@@ -295,7 +295,7 @@ describe("Date Filter", () => {
it("has correct short week days for pt-Br", async () => {
window.mx = createMXObjectMock("pt_BR", "pt-BR");
- render();
+ render();
const input = screen.getByRole("textbox");
await act(async () => {
@@ -307,7 +307,7 @@ describe("Date Filter", () => {
it("has correct short week days for fi-FI and starts on monday", async () => {
window.mx = createMXObjectMock("fi_FI", "fi-FI", 1);
- render();
+ render();
const input = screen.getByRole("textbox");
await act(async () => {
@@ -319,7 +319,7 @@ describe("Date Filter", () => {
it("has correct short week days for fi-FI", async () => {
window.mx = createMXObjectMock("fi_FI", "fi-FI");
- render();
+ render();
const input = screen.getByRole("textbox");
await act(async () => {
diff --git a/packages/pluggableWidgets/datagrid-dropdown-filter-web/src/__tests__/DatagridDropdownFilter.spec.tsx b/packages/pluggableWidgets/datagrid-dropdown-filter-web/src/__tests__/DatagridDropdownFilter.spec.tsx
index a9574add32..02a7b4f0b9 100644
--- a/packages/pluggableWidgets/datagrid-dropdown-filter-web/src/__tests__/DatagridDropdownFilter.spec.tsx
+++ b/packages/pluggableWidgets/datagrid-dropdown-filter-web/src/__tests__/DatagridDropdownFilter.spec.tsx
@@ -1,7 +1,7 @@
import { EnumFilterStore } from "@mendix/widget-plugin-dropdown-filter/stores/EnumFilterStore";
import { FilterAPI } from "@mendix/widget-plugin-filtering/context";
import { ObservableFilterHost } from "@mendix/widget-plugin-filtering/typings/ObservableFilterHost";
-import { dynamicValue, listAttribute } from "@mendix/widget-plugin-test-utils";
+import { dynamic, listAttribute } from "@mendix/widget-plugin-test-utils";
import "@testing-library/jest-dom";
import { render, waitFor } from "@testing-library/react";
import { AssociationMetaData, AttributeMetaData } from "mendix";
@@ -23,9 +23,9 @@ const commonProps: DatagridDropdownFilterContainerProps = {
filterable: false,
multiSelect: false,
clearable: false,
- emptySelectionCaption: dynamicValue("Select"),
- emptyOptionCaption: dynamicValue("None"),
- ariaLabel: dynamicValue("AriaLabel"),
+ emptySelectionCaption: dynamic.available("Select"),
+ emptyOptionCaption: dynamic.available("None"),
+ ariaLabel: dynamic.available("AriaLabel"),
selectedItemsStyle: "text",
selectionMethod: "checkbox",
refCaptionSource: "attr"
diff --git a/packages/pluggableWidgets/datagrid-dropdown-filter-web/src/__tests__/__snapshots__/DatagridDropdownFilter.spec.tsx.snap b/packages/pluggableWidgets/datagrid-dropdown-filter-web/src/__tests__/__snapshots__/DatagridDropdownFilter.spec.tsx.snap
index 30a3fc29b9..5edf28105f 100644
--- a/packages/pluggableWidgets/datagrid-dropdown-filter-web/src/__tests__/__snapshots__/DatagridDropdownFilter.spec.tsx.snap
+++ b/packages/pluggableWidgets/datagrid-dropdown-filter-web/src/__tests__/__snapshots__/DatagridDropdownFilter.spec.tsx.snap
@@ -1,4 +1,4 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`Dropdown Filter with single instance with single attribute renders correctly 1`] = `
diff --git a/packages/pluggableWidgets/datagrid-number-filter-web/src/components/__tests__/DatagridNumberFilter.spec.tsx b/packages/pluggableWidgets/datagrid-number-filter-web/src/components/__tests__/DatagridNumberFilter.spec.tsx
index ac6a05b69e..d147b9e01b 100644
--- a/packages/pluggableWidgets/datagrid-number-filter-web/src/components/__tests__/DatagridNumberFilter.spec.tsx
+++ b/packages/pluggableWidgets/datagrid-number-filter-web/src/components/__tests__/DatagridNumberFilter.spec.tsx
@@ -12,7 +12,6 @@ import { ObservableFilterHost } from "@mendix/widget-plugin-filtering/typings/Ob
import {
actionValue,
dynamic,
- dynamicValue,
EditableValueBuilder,
ListAttributeValueBuilder
} from "@mendix/widget-plugin-test-utils";
@@ -126,20 +125,20 @@ describe("Number Filter", () => {
describe("with defaultValue", () => {
it("initializes with defaultValue", () => {
- render((new Big(100))} />);
+ render();
expect(screen.getByRole("textbox")).toHaveValue("100");
});
it("do not sync value and defaultValue when defaultValue changes from undefined to number", () => {
const { rerender } = render();
expect(screen.getByRole("textbox")).toHaveValue("");
- rerender((new Big(100))} />);
+ rerender();
expect(screen.getByRole("textbox")).toHaveValue("");
});
it("do not sync value and defaultValue when defaultValue changes from number to undefined", async () => {
const { rerender } = render(
- (new Big(100))} />
+
);
expect(screen.getByRole("textbox")).toHaveValue("100");
rerender();
@@ -150,7 +149,7 @@ describe("Number Filter", () => {
it("clears value when external reset all event is triggered", async () => {
const attribute = new EditableValueBuilder().build();
- const value = dynamic(Big(123));
+ const value = dynamic.available(Big(123));
const { getByRole } = render(
);
diff --git a/packages/pluggableWidgets/datagrid-text-filter-web/src/components/__tests__/DatagridTextFilter.spec.tsx b/packages/pluggableWidgets/datagrid-text-filter-web/src/components/__tests__/DatagridTextFilter.spec.tsx
index a35183e18d..5e73dcfe4a 100644
--- a/packages/pluggableWidgets/datagrid-text-filter-web/src/components/__tests__/DatagridTextFilter.spec.tsx
+++ b/packages/pluggableWidgets/datagrid-text-filter-web/src/components/__tests__/DatagridTextFilter.spec.tsx
@@ -11,7 +11,7 @@ import { StringInputFilterStore } from "@mendix/widget-plugin-filtering/stores/i
import { ObservableFilterHost } from "@mendix/widget-plugin-filtering/typings/ObservableFilterHost";
import {
actionValue,
- dynamicValue,
+ dynamic,
EditableValueBuilder,
ListAttributeValueBuilder
} from "@mendix/widget-plugin-test-utils";
@@ -79,22 +79,22 @@ describe("Text Filter", () => {
const { rerender } = render();
expect(screen.getByRole("textbox")).toHaveValue("");
- rerender(("xyz")} />);
+ rerender();
expect(screen.getByRole("textbox")).toHaveValue("");
});
it("don't sync value when defaultValue changes from string to string", async () => {
const { rerender } = render(
- ("abc")} />
+
);
expect(screen.getByRole("textbox")).toHaveValue("abc");
- rerender(("xyz")} />);
+ rerender();
expect(screen.getByRole("textbox")).toHaveValue("abc");
});
it("don't sync value when defaultValue changes from string to undefined", async () => {
const { rerender } = render(
- ("abc")} />
+
);
expect(screen.getByRole("textbox")).toHaveValue("abc");
rerender();
@@ -103,7 +103,7 @@ describe("Text Filter", () => {
it("clears value when external reset all event is triggered with defaultValue", async () => {
const attribute = new EditableValueBuilder().build();
- const value = dynamicValue("a string");
+ const value = dynamic.available("a string");
const { getByRole } = render(
);
@@ -133,7 +133,7 @@ describe("Text Filter", () => {
});
it("sets value when external set value event is triggered with defaultValue", async () => {
const attribute = new EditableValueBuilder().build();
- const value = dynamicValue("a string");
+ const value = dynamic.available("a string");
const { getByRole } = render(
);
diff --git a/packages/pluggableWidgets/datagrid-web/src/components/__tests__/Header.spec.tsx b/packages/pluggableWidgets/datagrid-web/src/components/__tests__/Header.spec.tsx
index 8700700918..6a89633dc6 100644
--- a/packages/pluggableWidgets/datagrid-web/src/components/__tests__/Header.spec.tsx
+++ b/packages/pluggableWidgets/datagrid-web/src/components/__tests__/Header.spec.tsx
@@ -146,7 +146,7 @@ describe("Header", () => {
it("renders the structure correctly when value is empty", () => {
const columnsType = column("Column 1", col => {
- col.header = dynamic(" ");
+ col.header = dynamic.available(" ");
});
const props = mockContainerProps({
columns: [columnsType]
diff --git a/packages/pluggableWidgets/datagrid-web/src/features/data-export/__tests__/cell-readers.spec.ts b/packages/pluggableWidgets/datagrid-web/src/features/data-export/__tests__/cell-readers.spec.ts
index 73f8c2ef1f..cc85e44750 100644
--- a/packages/pluggableWidgets/datagrid-web/src/features/data-export/__tests__/cell-readers.spec.ts
+++ b/packages/pluggableWidgets/datagrid-web/src/features/data-export/__tests__/cell-readers.spec.ts
@@ -40,7 +40,7 @@ describe("cell-readers", () => {
c.showContentAs = "attribute";
c.attribute = listAttribute(() => new Big("1234.56"));
c.exportType = "number";
- c.exportNumberFormat = dynamic("#,##0.00");
+ c.exportNumberFormat = dynamic.available("#,##0.00");
});
const cell = readSingleCell(col);
expect(cell.t).toBe("n");
@@ -74,7 +74,7 @@ describe("cell-readers", () => {
c.showContentAs = "attribute";
c.attribute = listAttribute(() => testDate);
c.exportType = "date";
- c.exportDateFormat = dynamic("yyyy-mm-dd");
+ c.exportDateFormat = dynamic.available("yyyy-mm-dd");
});
const cell = readSingleCell(col);
expect(cell.t).toBe("d");
@@ -164,7 +164,7 @@ describe("cell-readers", () => {
c.showContentAs = "customContent";
c.exportValue = listExpression(() => "1234.56");
c.exportType = "number";
- c.exportNumberFormat = dynamic("#,##0.00");
+ c.exportNumberFormat = dynamic.available("#,##0.00");
});
const cell = readSingleCell(col);
expect(cell.t).toBe("n");
@@ -221,7 +221,7 @@ describe("cell-readers", () => {
c.showContentAs = "customContent";
c.exportValue = listExpression(() => "2024-06-15T00:00:00.000Z");
c.exportType = "date";
- c.exportDateFormat = dynamic("yyyy-mm-dd");
+ c.exportDateFormat = dynamic.available("yyyy-mm-dd");
});
const cell = readSingleCell(col);
expect(cell.t).toBe("d");
@@ -246,7 +246,7 @@ describe("cell-readers", () => {
c.showContentAs = "customContent";
c.exportValue = listExpression(() => "not-a-date");
c.exportType = "date";
- c.exportDateFormat = dynamic("yyyy-mm-dd");
+ c.exportDateFormat = dynamic.available("yyyy-mm-dd");
});
const cell = readSingleCell(col);
expect(cell.t).toBe("s");
@@ -258,7 +258,7 @@ describe("cell-readers", () => {
c.showContentAs = "customContent";
c.exportValue = listExpression(() => "");
c.exportType = "date";
- c.exportDateFormat = dynamic("yyyy-mm-dd");
+ c.exportDateFormat = dynamic.available("yyyy-mm-dd");
});
const cell = readSingleCell(col);
expect(cell.t).toBe("s");
@@ -351,7 +351,7 @@ describe("cell-readers", () => {
c.showContentAs = "attribute";
c.attribute = listAttribute(() => new Big("9999999999999999999"));
c.exportType = "number";
- c.exportNumberFormat = dynamic("0");
+ c.exportNumberFormat = dynamic.available("0");
});
const cell = readSingleCell(col);
expect(cell.t).toBe("s");
@@ -376,7 +376,7 @@ describe("cell-readers", () => {
c.showContentAs = "attribute";
c.attribute = listAttribute(() => testDate);
c.exportType = "date";
- c.exportDateFormat = dynamic("dd-mmm-yyyy");
+ c.exportDateFormat = dynamic.available("dd-mmm-yyyy");
});
const cell = readSingleCell(col);
expect(cell.t).toBe("d");
@@ -390,7 +390,7 @@ describe("cell-readers", () => {
c.showContentAs = "attribute";
c.attribute = listAttribute(() => testDate);
c.exportType = "date";
- c.exportDateFormat = dynamic("yyyy-mm-dd hh:mm:ss");
+ c.exportDateFormat = dynamic.available("yyyy-mm-dd hh:mm:ss");
});
const cell = readSingleCell(col);
expect(cell.t).toBe("d");
@@ -402,7 +402,7 @@ describe("cell-readers", () => {
c.showContentAs = "customContent";
c.exportValue = listExpression(() => "2024-06-15T10:30:00Z");
c.exportType = "date";
- c.exportDateFormat = dynamic("dd-mmm-yyyy");
+ c.exportDateFormat = dynamic.available("dd-mmm-yyyy");
});
const cell = readSingleCell(col);
expect(cell.t).toBe("d");
@@ -414,7 +414,7 @@ describe("cell-readers", () => {
c.showContentAs = "customContent";
c.exportValue = listExpression(() => "2024-06-15T10:30:00Z");
c.exportType = "date";
- c.exportDateFormat = dynamic("yyyy-mm-dd hh:mm:ss");
+ c.exportDateFormat = dynamic.available("yyyy-mm-dd hh:mm:ss");
});
const cell = readSingleCell(col);
expect(cell.t).toBe("d");
diff --git a/packages/pluggableWidgets/datagrid-web/src/utils/test-utils.tsx b/packages/pluggableWidgets/datagrid-web/src/utils/test-utils.tsx
index 006aa771f8..d18c6e9ac5 100644
--- a/packages/pluggableWidgets/datagrid-web/src/utils/test-utils.tsx
+++ b/packages/pluggableWidgets/datagrid-web/src/utils/test-utils.tsx
@@ -10,7 +10,7 @@ export const column = (header = "Test", patch?: (col: ColumnsType) => void): Col
attribute: listAttribute(() => "Attr value"),
dynamicText: listExpression(() => "Dynamic text"),
draggable: false,
- header: dynamic(header),
+ header: dynamic.available(header),
hidable: "no" as const,
resizable: false,
showContentAs: "attribute",
@@ -18,7 +18,7 @@ export const column = (header = "Test", patch?: (col: ColumnsType) => void): Col
sortable: false,
width: "autoFill" as const,
wrapText: false,
- visible: dynamic(true),
+ visible: dynamic.available(true),
minWidth: "auto",
minWidthLimit: 100,
allowEventPropagation: true,
@@ -82,9 +82,9 @@ export function mockContainerProps(overrides?: Partial):
configurationStorageType: "attribute",
configurationAttribute: undefined,
storeFiltersInPersonalization: true,
- selectAllText: dynamic("Select all items"),
- selectAllTemplate: dynamic("Select all %d items"),
- allSelectedText: dynamic("All items selected"),
+ selectAllText: dynamic.available("Select all items"),
+ selectAllTemplate: dynamic.available("Select all %d items"),
+ allSelectedText: dynamic.available("All items selected"),
useCustomPagination: false,
customPagination: undefined,
...overrides
diff --git a/packages/pluggableWidgets/dropdown-sort-web/src/components/__test__/DropdownSort.spec.tsx b/packages/pluggableWidgets/dropdown-sort-web/src/components/__test__/DropdownSort.spec.tsx
index dad836d8ac..731728dd26 100644
--- a/packages/pluggableWidgets/dropdown-sort-web/src/components/__test__/DropdownSort.spec.tsx
+++ b/packages/pluggableWidgets/dropdown-sort-web/src/components/__test__/DropdownSort.spec.tsx
@@ -1,8 +1,8 @@
-import { getGlobalSortContext, SortAPI } from "@mendix/widget-plugin-sorting/react/context";
-import { SortStoreHost } from "@mendix/widget-plugin-sorting/stores/SortStoreHost";
-import { attrId, dynamicValue, ListAttributeValueBuilder } from "@mendix/widget-plugin-test-utils";
import { fireEvent, render } from "@testing-library/react";
import { ReactElement } from "react";
+import { getGlobalSortContext, SortAPI } from "@mendix/widget-plugin-sorting/react/context";
+import { SortStoreHost } from "@mendix/widget-plugin-sorting/stores/SortStoreHost";
+import { attrId, dynamic, ListAttributeValueBuilder } from "@mendix/widget-plugin-test-utils";
import { AttributesType, DropdownSortContainerProps } from "../../../typings/DropdownSortProps";
import { DropdownSort } from "../../DropdownSort";
@@ -21,11 +21,11 @@ const createAPI = (observer: SortStoreHost): SortAPI => ({
const mockAttributes = (): AttributesType[] => [
{
attribute: new ListAttributeValueBuilder().withId(attrId("1")).withType("String").withSortable(true).build(),
- caption: dynamicValue("Option 1")
+ caption: dynamic.available("Option 1")
},
{
attribute: new ListAttributeValueBuilder().withId(attrId("2")).withType("Decimal").withSortable(true).build(),
- caption: dynamicValue("Option 2")
+ caption: dynamic.available("Option 2")
}
];
diff --git a/packages/pluggableWidgets/events-web/src/__tests__/AppEvents.spec.tsx b/packages/pluggableWidgets/events-web/src/__tests__/AppEvents.spec.tsx
index 02e155aa25..ab2960281e 100644
--- a/packages/pluggableWidgets/events-web/src/__tests__/AppEvents.spec.tsx
+++ b/packages/pluggableWidgets/events-web/src/__tests__/AppEvents.spec.tsx
@@ -1,4 +1,4 @@
-import { actionValue, dynamicValue } from "@mendix/widget-plugin-test-utils";
+import { actionValue, dynamic } from "@mendix/widget-plugin-test-utils";
import "@testing-library/jest-dom";
import { render } from "@testing-library/react";
import { EventsContainerProps } from "../../typings/EventsProps";
@@ -13,16 +13,16 @@ describe("App events (load)", () => {
onComponentLoad: actionValue(),
componentLoadDelayParameterType: "number",
componentLoadDelay: 0,
- componentLoadDelayExpression: dynamicValue(),
+ componentLoadDelayExpression: dynamic.unavailable(),
componentLoadRepeat: false,
componentLoadRepeatIntervalParameterType: "number",
componentLoadRepeatInterval: 0,
- componentLoadRepeatIntervalExpression: dynamicValue(),
+ componentLoadRepeatIntervalExpression: dynamic.unavailable(),
onEventChangeAttribute: undefined,
onEventChange: undefined,
onEventChangeDelayParameterType: "number",
onEventChangeDelay: 0,
- onEventChangeDelayExpression: dynamicValue()
+ onEventChangeDelayExpression: dynamic.unavailable()
};
});
it("render app events", async () => {
diff --git a/packages/pluggableWidgets/file-uploader-web/src/stores/__tests__/FileUploaderStore.spec.ts b/packages/pluggableWidgets/file-uploader-web/src/stores/__tests__/FileUploaderStore.spec.ts
index 722ea57bdf..148fbca112 100644
--- a/packages/pluggableWidgets/file-uploader-web/src/stores/__tests__/FileUploaderStore.spec.ts
+++ b/packages/pluggableWidgets/file-uploader-web/src/stores/__tests__/FileUploaderStore.spec.ts
@@ -32,29 +32,33 @@ function buildProps(overrides: Partial = {}): FileUp
createFileAction: actionValue(true, false),
createImageAction: actionValue(true, false),
allowedFileFormats: [],
- maxFilesPerUpload: dynamic(new Big(5)),
+ maxFilesPerUpload: dynamic.available(new Big(5)),
maxFilesPerBatch: unavailableDynamic(),
maxFileSize: 25,
objectCreationTimeout: 10,
- dropzoneIdleMessage: dynamic("Drag and drop files here"),
- dropzoneAcceptedMessage: dynamic("All files can be uploaded."),
- dropzoneRejectedMessage: dynamic("Some files may not be uploadable."),
- uploadInProgressMessage: dynamic("Uploading..."),
- uploadQueuedMessage: dynamic("Waiting..."),
- uploadSuccessMessage: dynamic("Uploaded successfully."),
- uploadFailureGenericMessage: dynamic("An error occurred during uploading."),
- uploadFailureInvalidFileFormatMessage: dynamic("File format is not supported, supported formats are ###."),
- uploadFailureFileIsTooBigMessage: dynamic("File size exceeds the maximum limit of ### megabytes."),
- uploadFailureTooManyFilesMessage: dynamic("Too many files added. Only ### files per upload are allowed."),
- uploadLimitReachedMessage: dynamic("Maximum file count of ### reached."),
- unavailableCreateActionMessage: dynamic(
+ dropzoneIdleMessage: dynamic.available("Drag and drop files here"),
+ dropzoneAcceptedMessage: dynamic.available("All files can be uploaded."),
+ dropzoneRejectedMessage: dynamic.available("Some files may not be uploadable."),
+ uploadInProgressMessage: dynamic.available("Uploading..."),
+ uploadQueuedMessage: dynamic.available("Waiting..."),
+ uploadSuccessMessage: dynamic.available("Uploaded successfully."),
+ uploadFailureGenericMessage: dynamic.available("An error occurred during uploading."),
+ uploadFailureInvalidFileFormatMessage: dynamic.available(
+ "File format is not supported, supported formats are ###."
+ ),
+ uploadFailureFileIsTooBigMessage: dynamic.available("File size exceeds the maximum limit of ### megabytes."),
+ uploadFailureTooManyFilesMessage: dynamic.available(
+ "Too many files added. Only ### files per upload are allowed."
+ ),
+ uploadLimitReachedMessage: dynamic.available("Maximum file count of ### reached."),
+ unavailableCreateActionMessage: dynamic.available(
"Can't upload files at this time. Please contact your system administrator."
),
- downloadButtonTextMessage: dynamic("Download this file"),
- removeButtonTextMessage: dynamic("Remove this file"),
- retryButtonTextMessage: dynamic("Retry upload"),
- removeSuccessMessage: dynamic("Removed successfully."),
- removeErrorMessage: dynamic("An error occurred while removing this file."),
+ downloadButtonTextMessage: dynamic.available("Download this file"),
+ removeButtonTextMessage: dynamic.available("Remove this file"),
+ retryButtonTextMessage: dynamic.available("Retry upload"),
+ removeSuccessMessage: dynamic.available("Removed successfully."),
+ removeErrorMessage: dynamic.available("An error occurred while removing this file."),
enableCustomButtons: false,
customButtons: [],
onUploadSuccessFile: undefined,
@@ -239,7 +243,7 @@ describe("FileStore.newRejectedFile", () => {
describe("FileStore.canRetry", () => {
test("true when file is rejected and limit is not full", () => {
const store = buildStore({
- maxFilesPerUpload: dynamic(new Big(3)),
+ maxFilesPerUpload: dynamic.available(new Big(3)),
maxFilesPerBatch: unavailableDynamic()
});
const file = FileStore.newRejectedFile(makeFile("x.txt"), store);
@@ -250,7 +254,7 @@ describe("FileStore.canRetry", () => {
test("false when file is rejected but limit is full", () => {
const store = buildStore({
- maxFilesPerUpload: dynamic(new Big(2)),
+ maxFilesPerUpload: dynamic.available(new Big(2)),
maxFilesPerBatch: unavailableDynamic()
});
store.objectCreationHelper.request = jest.fn().mockReturnValue(new Promise(() => {}));
@@ -275,7 +279,7 @@ describe("FileStore.canRetry", () => {
describe("FileStore.canRetry — reacts to freed slots", () => {
test("flips to true when an active file errors and frees a slot", async () => {
const store = buildStore({
- maxFilesPerUpload: dynamic(new Big(1)),
+ maxFilesPerUpload: dynamic.available(new Big(1)),
maxFilesPerBatch: unavailableDynamic()
});
store.objectCreationHelper.request = jest.fn().mockRejectedValueOnce(new Error("fail"));
@@ -296,7 +300,7 @@ describe("FileStore.canRetry — reacts to freed slots", () => {
test("flips to true when an active file is removed and frees a slot", () => {
const store = buildStore({
- maxFilesPerUpload: dynamic(new Big(1)),
+ maxFilesPerUpload: dynamic.available(new Big(1)),
maxFilesPerBatch: unavailableDynamic()
});
store.objectCreationHelper.request = jest.fn().mockReturnValue(new Promise(() => {}));
@@ -316,7 +320,7 @@ describe("FileStore.canRetry — reacts to freed slots", () => {
test("both rejected files get canRetry=true when one slot frees", async () => {
const store = buildStore({
- maxFilesPerUpload: dynamic(new Big(2)),
+ maxFilesPerUpload: dynamic.available(new Big(2)),
maxFilesPerBatch: unavailableDynamic()
});
store.objectCreationHelper.request = jest
@@ -346,7 +350,7 @@ describe("FileStore.canRetry — reacts to freed slots", () => {
describe("FileStore.retry", () => {
test("transitions rejected file to uploading via queue reaction", () => {
const store = buildStore({
- maxFilesPerUpload: dynamic(new Big(3)),
+ maxFilesPerUpload: dynamic.available(new Big(3)),
maxFilesPerBatch: unavailableDynamic()
});
store.objectCreationHelper.request = jest.fn().mockReturnValue(new Promise(() => {}));
@@ -373,7 +377,7 @@ describe("FileStore.retry", () => {
test("does nothing when total limit is full (limit reached)", () => {
const store = buildStore({
- maxFilesPerUpload: dynamic(new Big(1)),
+ maxFilesPerUpload: dynamic.available(new Big(1)),
maxFilesPerBatch: unavailableDynamic()
});
store.objectCreationHelper.request = jest.fn().mockReturnValue(new Promise(() => {}));
@@ -414,8 +418,8 @@ describe("FileUploaderStore.queuedCount", () => {
test("increases when processDrop adds queued files", () => {
const store = buildStore({
- maxFilesPerUpload: dynamic(new Big(10)),
- maxFilesPerBatch: dynamic(new Big(1))
+ maxFilesPerUpload: dynamic.available(new Big(10)),
+ maxFilesPerBatch: dynamic.available(new Big(1))
});
store.objectCreationHelper.request = jest.fn().mockReturnValue(new Promise(() => {}));
@@ -430,13 +434,13 @@ describe("FileUploaderStore.queuedCount", () => {
describe("FileUploaderStore — renamed properties", () => {
test("maxTotalFiles reads from maxFilesPerUpload XML prop", () => {
- const store = buildStore({ maxFilesPerUpload: dynamic(new Big(7)) });
+ const store = buildStore({ maxFilesPerUpload: dynamic.available(new Big(7)) });
expect(store.maxTotalFiles).toBe(7);
});
test("maxConcurrentUploads reads from maxFilesPerBatch XML prop", () => {
- const store = buildStore({ maxFilesPerBatch: dynamic(new Big(3)) });
+ const store = buildStore({ maxFilesPerBatch: dynamic.available(new Big(3)) });
expect(store.maxConcurrentUploads).toBe(3);
});
@@ -474,7 +478,7 @@ describe("FileUploaderStore — removed legacy methods", () => {
describe("FileUploaderStore.processDrop — pure classifier", () => {
test("accepted files within capacity enter upload pipeline (queued or uploading)", () => {
- const store = buildStore({ maxFilesPerUpload: dynamic(new Big(5)) });
+ const store = buildStore({ maxFilesPerUpload: dynamic.available(new Big(5)) });
store.processDrop(
[1, 2, 3].map(n => makeFile(`file${n}.txt`)),
@@ -486,7 +490,7 @@ describe("FileUploaderStore.processDrop — pure classifier", () => {
});
test("files exceeding maxTotalFiles go to 'rejected' status", () => {
- const store = buildStore({ maxFilesPerUpload: dynamic(new Big(2)) });
+ const store = buildStore({ maxFilesPerUpload: dynamic.available(new Big(2)) });
store.processDrop(
[1, 2, 3, 4].map(n => makeFile(`file${n}.txt`)),
@@ -510,7 +514,10 @@ describe("FileUploaderStore.processDrop — pure classifier", () => {
});
test("no file gets 'batchExceeded' treatment — excess files enter pipeline or rejected only", () => {
- const store = buildStore({ maxFilesPerBatch: dynamic(new Big(2)), maxFilesPerUpload: dynamic(new Big(10)) });
+ const store = buildStore({
+ maxFilesPerBatch: dynamic.available(new Big(2)),
+ maxFilesPerUpload: dynamic.available(new Big(10))
+ });
store.processDrop(
[1, 2, 3, 4].map(n => makeFile(`file${n}.txt`)),
@@ -522,7 +529,7 @@ describe("FileUploaderStore.processDrop — pure classifier", () => {
});
test("no file has errorType set after processDrop", () => {
- const store = buildStore({ maxFilesPerUpload: dynamic(new Big(2)) });
+ const store = buildStore({ maxFilesPerUpload: dynamic.available(new Big(2)) });
store.processDrop(
[1, 2, 3, 4].map(n => makeFile(`file${n}.txt`)),
@@ -535,8 +542,8 @@ describe("FileUploaderStore.processDrop — pure classifier", () => {
test("drop with maxConcurrentUploads=2: exactly 2 start uploading, rest stay queued", () => {
const store = buildStore({
- maxFilesPerUpload: dynamic(new Big(10)),
- maxFilesPerBatch: dynamic(new Big(2))
+ maxFilesPerUpload: dynamic.available(new Big(10)),
+ maxFilesPerBatch: dynamic.available(new Big(2))
});
store.objectCreationHelper.request = jest.fn().mockRejectedValue(new Error("no server"));
@@ -551,7 +558,7 @@ describe("FileUploaderStore.processDrop — pure classifier", () => {
test("drop with no concurrent limit: all files start uploading immediately", () => {
const store = buildStore({
- maxFilesPerUpload: dynamic(new Big(10)),
+ maxFilesPerUpload: dynamic.available(new Big(10)),
maxFilesPerBatch: unavailableDynamic()
});
store.objectCreationHelper.request = jest.fn().mockRejectedValue(new Error("no server"));
@@ -571,8 +578,8 @@ describe("FileUploaderStore.processDrop — pure classifier", () => {
describe("FileUploaderStore — Reaction 3: queue auto-drains when queued files arrive", () => {
test("files queued by processDrop start uploading without any manual drain call", () => {
const store = buildStore({
- maxFilesPerUpload: dynamic(new Big(10)),
- maxFilesPerBatch: dynamic(new Big(1))
+ maxFilesPerUpload: dynamic.available(new Big(10)),
+ maxFilesPerBatch: dynamic.available(new Big(1))
});
store.objectCreationHelper.request = jest.fn().mockReturnValue(new Promise(() => {}));
@@ -586,8 +593,8 @@ describe("FileUploaderStore — Reaction 3: queue auto-drains when queued files
test("manually setting a file to queued triggers upload automatically", () => {
const store = buildStore({
- maxFilesPerUpload: dynamic(new Big(10)),
- maxFilesPerBatch: dynamic(new Big(2))
+ maxFilesPerUpload: dynamic.available(new Big(10)),
+ maxFilesPerBatch: dynamic.available(new Big(2))
});
store.objectCreationHelper.request = jest.fn().mockReturnValue(new Promise(() => {}));
@@ -602,7 +609,7 @@ describe("FileUploaderStore — Reaction 3: queue auto-drains when queued files
test("rejected file does NOT auto-promote when a slot frees — manual retry required", () => {
const store = buildStore({
- maxFilesPerUpload: dynamic(new Big(2)),
+ maxFilesPerUpload: dynamic.available(new Big(2)),
maxFilesPerBatch: unavailableDynamic()
});
store.objectCreationHelper.request = jest.fn().mockReturnValue(new Promise(() => {}));
@@ -625,14 +632,14 @@ describe("FileUploaderStore — Reaction 3: queue auto-drains when queued files
describe("FileUploaderStore.isFileUploadLimitReached", () => {
test("false when no files have been dropped", () => {
- const store = buildStore({ maxFilesPerUpload: dynamic(new Big(3)) });
+ const store = buildStore({ maxFilesPerUpload: dynamic.available(new Big(3)) });
expect(store.isFileUploadLimitReached).toBe(false);
});
test("false when below the configured limit", () => {
const store = buildStore({
- maxFilesPerUpload: dynamic(new Big(3)),
+ maxFilesPerUpload: dynamic.available(new Big(3)),
maxFilesPerBatch: unavailableDynamic()
});
store.objectCreationHelper.request = jest.fn().mockReturnValue(new Promise(() => {}));
@@ -644,7 +651,7 @@ describe("FileUploaderStore.isFileUploadLimitReached", () => {
test("true when exactly at the limit", () => {
const store = buildStore({
- maxFilesPerUpload: dynamic(new Big(2)),
+ maxFilesPerUpload: dynamic.available(new Big(2)),
maxFilesPerBatch: unavailableDynamic()
});
store.objectCreationHelper.request = jest.fn().mockReturnValue(new Promise(() => {}));
@@ -656,7 +663,7 @@ describe("FileUploaderStore.isFileUploadLimitReached", () => {
test("rejected files (over cap) do not contribute to active count", () => {
const store = buildStore({
- maxFilesPerUpload: dynamic(new Big(2)),
+ maxFilesPerUpload: dynamic.available(new Big(2)),
maxFilesPerBatch: unavailableDynamic()
});
store.objectCreationHelper.request = jest.fn().mockReturnValue(new Promise(() => {}));
@@ -668,7 +675,7 @@ describe("FileUploaderStore.isFileUploadLimitReached", () => {
});
test("validationError files do not count toward active count", () => {
- const store = buildStore({ maxFilesPerUpload: dynamic(new Big(2)) });
+ const store = buildStore({ maxFilesPerUpload: dynamic.available(new Big(2)) });
store.processDrop([], [
{ file: makeFile("bad1.exe"), errors: [{ code: "file-invalid-type", message: "" }] },
@@ -682,7 +689,7 @@ describe("FileUploaderStore.isFileUploadLimitReached", () => {
test("uploadingError files do not count toward active count", async () => {
const store = buildStore({
- maxFilesPerUpload: dynamic(new Big(2)),
+ maxFilesPerUpload: dynamic.available(new Big(2)),
maxFilesPerBatch: unavailableDynamic()
});
store.objectCreationHelper.request = jest.fn().mockRejectedValue(new Error("fail"));
@@ -698,7 +705,7 @@ describe("FileUploaderStore.isFileUploadLimitReached", () => {
test("false when maxTotalFiles is 0 (unlimited), regardless of file count", () => {
const store = buildStore({
- maxFilesPerUpload: dynamic(new Big(0)),
+ maxFilesPerUpload: dynamic.available(new Big(0)),
maxFilesPerBatch: unavailableDynamic()
});
store.objectCreationHelper.request = jest.fn().mockReturnValue(new Promise(() => {}));
@@ -725,7 +732,7 @@ describe("FileUploaderStore.isFileUploadLimitReached", () => {
describe("FileUploaderStore.sortedFiles", () => {
test("validationError files sort to the end", () => {
- const store = buildStore({ maxFilesPerUpload: dynamic(new Big(10)) });
+ const store = buildStore({ maxFilesPerUpload: dynamic.available(new Big(10)) });
// First drop an accepted file, then a validation error — error ends up at index 0
store.processDrop([makeFile("good.txt")], []);
@@ -741,7 +748,7 @@ describe("FileUploaderStore.sortedFiles", () => {
});
test("does not mutate the original files array", () => {
- const store = buildStore({ maxFilesPerUpload: dynamic(new Big(10)) });
+ const store = buildStore({ maxFilesPerUpload: dynamic.available(new Big(10)) });
store.processDrop([makeFile("good.txt")], []);
store.processDrop([], [
@@ -759,7 +766,7 @@ describe("FileUploaderStore.sortedFiles", () => {
describe("FileUploaderStore.promoteQueuedFiles", () => {
test("calls upload() on queued files up to maxConcurrentUploads", () => {
- const store = buildStore({ maxFilesPerBatch: dynamic(new Big(2)) });
+ const store = buildStore({ maxFilesPerBatch: dynamic.available(new Big(2)) });
const queued1 = { fileStatus: "queued", upload: jest.fn() } as any;
const queued2 = { fileStatus: "queued", upload: jest.fn() } as any;
@@ -774,7 +781,7 @@ describe("FileUploaderStore.promoteQueuedFiles", () => {
});
test("does not promote beyond available concurrent slots", () => {
- const store = buildStore({ maxFilesPerBatch: dynamic(new Big(2)) });
+ const store = buildStore({ maxFilesPerBatch: dynamic.available(new Big(2)) });
const uploading = { fileStatus: "uploading" } as any;
const queued1 = { fileStatus: "queued", upload: jest.fn() } as any;
@@ -790,7 +797,7 @@ describe("FileUploaderStore.promoteQueuedFiles", () => {
});
test("does nothing when all concurrent slots are occupied", () => {
- const store = buildStore({ maxFilesPerBatch: dynamic(new Big(2)) });
+ const store = buildStore({ maxFilesPerBatch: dynamic.available(new Big(2)) });
const uploading1 = { fileStatus: "uploading" } as any;
const uploading2 = { fileStatus: "uploading" } as any;
@@ -804,7 +811,7 @@ describe("FileUploaderStore.promoteQueuedFiles", () => {
});
test("does nothing when no queued files exist", () => {
- const store = buildStore({ maxFilesPerBatch: dynamic(new Big(2)) });
+ const store = buildStore({ maxFilesPerBatch: dynamic.available(new Big(2)) });
store.files.push({ fileStatus: "existingFile" } as any);
@@ -813,8 +820,8 @@ describe("FileUploaderStore.promoteQueuedFiles", () => {
test("queued file starts uploading when a concurrent slot frees up", async () => {
const store = buildStore({
- maxFilesPerBatch: dynamic(new Big(1)),
- maxFilesPerUpload: dynamic(new Big(10))
+ maxFilesPerBatch: dynamic.available(new Big(1)),
+ maxFilesPerUpload: dynamic.available(new Big(10))
});
const neverResolve = new Promise(() => {});
store.objectCreationHelper.request = jest.fn().mockReturnValue(neverResolve);
@@ -912,7 +919,7 @@ describe("FileUploaderStore.processDrop — error message mapping", () => {
describe("FileUploaderStore.updateProps", () => {
test("live increase of maxTotalFiles unblocks dropzone mid-session", () => {
const store = buildStore({
- maxFilesPerUpload: dynamic(new Big(2)),
+ maxFilesPerUpload: dynamic.available(new Big(2)),
maxFilesPerBatch: unavailableDynamic()
});
store.objectCreationHelper.request = jest.fn().mockReturnValue(new Promise(() => {}));
@@ -921,17 +928,17 @@ describe("FileUploaderStore.updateProps", () => {
expect(store.isFileUploadLimitReached).toBe(true);
store.updateProps(
- buildProps({ maxFilesPerUpload: dynamic(new Big(5)), maxFilesPerBatch: unavailableDynamic() })
+ buildProps({ maxFilesPerUpload: dynamic.available(new Big(5)), maxFilesPerBatch: unavailableDynamic() })
);
expect(store.isFileUploadLimitReached).toBe(false);
});
test("live decrease of maxConcurrentUploads is reflected immediately", () => {
- const store = buildStore({ maxFilesPerBatch: dynamic(new Big(4)) });
+ const store = buildStore({ maxFilesPerBatch: dynamic.available(new Big(4)) });
expect(store.maxConcurrentUploads).toBe(4);
- store.updateProps(buildProps({ maxFilesPerBatch: dynamic(new Big(1)) }));
+ store.updateProps(buildProps({ maxFilesPerBatch: dynamic.available(new Big(1)) }));
expect(store.maxConcurrentUploads).toBe(1);
});
@@ -942,8 +949,8 @@ describe("FileUploaderStore.updateProps", () => {
describe("FileUploaderStore.dispose", () => {
test("queue drain reaction stops firing after dispose", () => {
const store = buildStore({
- maxFilesPerUpload: dynamic(new Big(10)),
- maxFilesPerBatch: dynamic(new Big(1))
+ maxFilesPerUpload: dynamic.available(new Big(10)),
+ maxFilesPerBatch: dynamic.available(new Big(1))
});
const neverResolve = new Promise(() => {});
store.objectCreationHelper.request = jest.fn().mockReturnValue(neverResolve);
@@ -967,8 +974,8 @@ describe("FileUploaderStore.dispose", () => {
describe("upload queue — end-to-end", () => {
test("upload error frees concurrent slot and next queued file starts uploading", async () => {
const store = buildStore({
- maxFilesPerUpload: dynamic(new Big(10)),
- maxFilesPerBatch: dynamic(new Big(1))
+ maxFilesPerUpload: dynamic.available(new Big(10)),
+ maxFilesPerBatch: dynamic.available(new Big(1))
});
// First request fails, second hangs so we can assert the stable "uploading" state
const neverResolve = new Promise(() => {});
@@ -994,7 +1001,7 @@ describe("upload queue — end-to-end", () => {
test("upload errors do NOT auto-promote rejected files — user must retry manually", async () => {
const store = buildStore({
- maxFilesPerUpload: dynamic(new Big(2)),
+ maxFilesPerUpload: dynamic.available(new Big(2)),
maxFilesPerBatch: unavailableDynamic()
});
store.objectCreationHelper.request = jest
diff --git a/packages/pluggableWidgets/file-uploader-web/src/utils/__tests__/parseAllowedFormats.spec.ts b/packages/pluggableWidgets/file-uploader-web/src/utils/__tests__/parseAllowedFormats.spec.ts
index d23035117c..b9fded2ee9 100644
--- a/packages/pluggableWidgets/file-uploader-web/src/utils/__tests__/parseAllowedFormats.spec.ts
+++ b/packages/pluggableWidgets/file-uploader-web/src/utils/__tests__/parseAllowedFormats.spec.ts
@@ -1,4 +1,4 @@
-import { dynamicValue } from "@mendix/widget-plugin-test-utils";
+import { dynamic } from "@mendix/widget-plugin-test-utils";
import { AllowedFileFormatsType } from "../../../typings/FileUploaderProps";
import { parseAllowedFormats } from "../parseAllowedFormats";
@@ -7,28 +7,28 @@ describe("parseAllowedFormats", () => {
const input: AllowedFileFormatsType[] = [
{
configMode: "advanced",
- typeFormatDescription: dynamicValue("test"),
+ typeFormatDescription: dynamic.available("test"),
predefinedType: "pdfFile",
mimeType: "image/jpeg",
extensions: ".jpg,.jpeg"
},
{
configMode: "advanced",
- typeFormatDescription: dynamicValue("test2"),
+ typeFormatDescription: dynamic.available("test2"),
predefinedType: "pdfFile",
mimeType: "application/pdf",
extensions: ".pdf"
},
{
configMode: "advanced",
- typeFormatDescription: dynamicValue("test"),
+ typeFormatDescription: dynamic.available("test"),
predefinedType: "pdfFile",
mimeType: "text/*",
extensions: ""
},
{
configMode: "advanced",
- typeFormatDescription: dynamicValue("test2"),
+ typeFormatDescription: dynamic.available("test2"),
predefinedType: "pdfFile",
mimeType: "",
extensions: ".html,.txt"
@@ -56,14 +56,14 @@ describe("parseAllowedFormats", () => {
const input: AllowedFileFormatsType[] = [
{
configMode: "advanced",
- typeFormatDescription: dynamicValue("test"),
+ typeFormatDescription: dynamic.available("test"),
predefinedType: "pdfFile",
mimeType: "image/*",
extensions: ".jpg"
},
{
configMode: "advanced",
- typeFormatDescription: dynamicValue("test"),
+ typeFormatDescription: dynamic.available("test"),
predefinedType: "pdfFile",
mimeType: "image/*",
extensions: ".png"
@@ -84,7 +84,7 @@ describe("parseAllowedFormats", () => {
const input: AllowedFileFormatsType[] = [
{
configMode: "advanced",
- typeFormatDescription: dynamicValue("test"),
+ typeFormatDescription: dynamic.available("test"),
predefinedType: "pdfFile",
mimeType: "application-pdf",
extensions: ".pdf"
@@ -99,7 +99,7 @@ describe("parseAllowedFormats", () => {
const input: AllowedFileFormatsType[] = [
{
configMode: "advanced",
- typeFormatDescription: dynamicValue("special-extensions"),
+ typeFormatDescription: dynamic.available("special-extensions"),
predefinedType: "pdfFile",
mimeType: "application/x-custom",
extensions: ".tar-gz,.js-map,.c++"
@@ -117,7 +117,7 @@ describe("parseAllowedFormats", () => {
const input: AllowedFileFormatsType[] = [
{
configMode: "advanced",
- typeFormatDescription: dynamicValue("test"),
+ typeFormatDescription: dynamic.available("test"),
predefinedType: "pdfFile",
mimeType: "text/*",
extensions: ".txt,pdf"
@@ -133,7 +133,7 @@ describe("parseAllowedFormats", () => {
const input: AllowedFileFormatsType[] = [
{
configMode: "advanced",
- typeFormatDescription: dynamicValue("test"),
+ typeFormatDescription: dynamic.available("test"),
predefinedType: "pdfFile",
mimeType: "text/*",
extensions: ".txt,.cvs,abc"
@@ -149,7 +149,7 @@ describe("parseAllowedFormats", () => {
const input: AllowedFileFormatsType[] = [
{
configMode: "advanced",
- typeFormatDescription: dynamicValue("test"),
+ typeFormatDescription: dynamic.available("test"),
predefinedType: "pdfFile",
mimeType: "text/*",
extensions: ".txt,.config.json"
diff --git a/packages/pluggableWidgets/maps-web/src/model/services/__tests__/LocationResolver.integration.spec.ts b/packages/pluggableWidgets/maps-web/src/model/services/__tests__/LocationResolver.integration.spec.ts
index 915d4345bd..caaf84f79f 100644
--- a/packages/pluggableWidgets/maps-web/src/model/services/__tests__/LocationResolver.integration.spec.ts
+++ b/packages/pluggableWidgets/maps-web/src/model/services/__tests__/LocationResolver.integration.spec.ts
@@ -41,13 +41,13 @@ describe("LocationResolverService - Integration Tests", () => {
geodecodeApiKey: "test-key",
markers: [
{
- latitude: dynamic("40.7128"),
- longitude: dynamic("-74.0060"),
- title: dynamic("NYC")
+ latitude: dynamic.available("40.7128"),
+ longitude: dynamic.available("-74.0060"),
+ title: dynamic.available("NYC")
} as MarkersType,
{
- address: dynamic("Boston, MA"),
- title: dynamic("Boston")
+ address: dynamic.available("Boston, MA"),
+ title: dynamic.available("Boston")
} as MarkersType
]
}),
@@ -78,7 +78,7 @@ describe("LocationResolverService - Integration Tests", () => {
geodecodeApiKey: "test-key",
markers: [
{
- address: dynamic("New York, NY")
+ address: dynamic.available("New York, NY")
} as MarkersType
]
});
@@ -114,9 +114,9 @@ describe("LocationResolverService - Integration Tests", () => {
props: mockContainerProps({
geodecodeApiKey: "test-key",
markers: [
- { address: dynamic("NYC"), title: dynamic("A") } as MarkersType,
- { address: dynamic("NYC"), title: dynamic("B") } as MarkersType,
- { address: dynamic("NYC"), title: dynamic("C") } as MarkersType
+ { address: dynamic.available("NYC"), title: dynamic.available("A") } as MarkersType,
+ { address: dynamic.available("NYC"), title: dynamic.available("B") } as MarkersType,
+ { address: dynamic.available("NYC"), title: dynamic.available("C") } as MarkersType
]
}),
geocodeFunction: mockGeocode
@@ -139,7 +139,7 @@ describe("LocationResolverService - Integration Tests", () => {
geodecodeApiKey: "test-key",
markers: [
{
- address: dynamic("Invalid Address")
+ address: dynamic.available("Invalid Address")
} as MarkersType
]
}),
@@ -170,9 +170,9 @@ describe("LocationResolverService - Integration Tests", () => {
props: mockContainerProps({
geodecodeApiKey: "test-key",
markers: [
- { address: dynamic("NYC") } as MarkersType,
- { address: dynamic("Invalid") } as MarkersType,
- { address: dynamic("Boston") } as MarkersType
+ { address: dynamic.available("NYC") } as MarkersType,
+ { address: dynamic.available("Invalid") } as MarkersType,
+ { address: dynamic.available("Boston") } as MarkersType
]
}),
geocodeFunction: mockGeocode
@@ -197,9 +197,9 @@ describe("LocationResolverService - Integration Tests", () => {
props: mockContainerProps({
markers: [
{
- latitude: dynamic("40"),
- longitude: dynamic("-74"),
- title: dynamic("Static")
+ latitude: dynamic.available("40"),
+ longitude: dynamic.available("-74"),
+ title: dynamic.available("Static")
} as MarkersType
],
dynamicMarkers: [
@@ -279,8 +279,8 @@ describe("LocationResolverService - Integration Tests", () => {
props: mockContainerProps({
markers: [
{
- latitude: dynamic("40"),
- longitude: dynamic("-74"),
+ latitude: dynamic.available("40"),
+ longitude: dynamic.available("-74"),
onClick: {
execute: mockAction
}
diff --git a/packages/pluggableWidgets/maps-web/src/model/services/__tests__/LocationResolver.reactivity.spec.ts b/packages/pluggableWidgets/maps-web/src/model/services/__tests__/LocationResolver.reactivity.spec.ts
index 2fb6035239..37f6622508 100644
--- a/packages/pluggableWidgets/maps-web/src/model/services/__tests__/LocationResolver.reactivity.spec.ts
+++ b/packages/pluggableWidgets/maps-web/src/model/services/__tests__/LocationResolver.reactivity.spec.ts
@@ -30,8 +30,8 @@ describe("LocationResolverService - Reactivity Tests", () => {
props: mockContainerProps({
markers: [
{
- latitude: dynamic("40.7128"),
- longitude: dynamic("-74.0060")
+ latitude: dynamic.available("40.7128"),
+ longitude: dynamic.available("-74.0060")
} as MarkersType
]
}),
@@ -45,9 +45,9 @@ describe("LocationResolverService - Reactivity Tests", () => {
gateProvider.setProps(
mockContainerProps({
markers: [
- { latitude: dynamic("40"), longitude: dynamic("-74") } as MarkersType,
- { latitude: dynamic("41"), longitude: dynamic("-75") } as MarkersType,
- { latitude: dynamic("42"), longitude: dynamic("-76") } as MarkersType
+ { latitude: dynamic.available("40"), longitude: dynamic.available("-74") } as MarkersType,
+ { latitude: dynamic.available("41"), longitude: dynamic.available("-75") } as MarkersType,
+ { latitude: dynamic.available("42"), longitude: dynamic.available("-76") } as MarkersType
]
})
);
@@ -63,8 +63,8 @@ describe("LocationResolverService - Reactivity Tests", () => {
props: mockContainerProps({
markers: [
{
- latitude: dynamic("40"),
- longitude: dynamic("-74")
+ latitude: dynamic.available("40"),
+ longitude: dynamic.available("-74")
} as MarkersType
]
}),
@@ -94,8 +94,8 @@ describe("LocationResolverService - Reactivity Tests", () => {
props: mockContainerProps({
markers: [
{
- latitude: dynamic("40"),
- longitude: dynamic("-74")
+ latitude: dynamic.available("40"),
+ longitude: dynamic.available("-74")
} as MarkersType
]
}),
@@ -117,8 +117,8 @@ describe("LocationResolverService - Reactivity Tests", () => {
gateProvider.setProps(
mockContainerProps({
markers: [
- { latitude: dynamic("40"), longitude: dynamic("-74") } as MarkersType,
- { latitude: dynamic("41"), longitude: dynamic("-75") } as MarkersType
+ { latitude: dynamic.available("40"), longitude: dynamic.available("-74") } as MarkersType,
+ { latitude: dynamic.available("41"), longitude: dynamic.available("-75") } as MarkersType
]
})
);
@@ -136,9 +136,9 @@ describe("LocationResolverService - Reactivity Tests", () => {
const markers = [
{
- latitude: dynamic("40"),
- longitude: dynamic("-74"),
- title: dynamic("Test")
+ latitude: dynamic.available("40"),
+ longitude: dynamic.available("-74"),
+ title: dynamic.available("Test")
} as MarkersType
];
@@ -175,8 +175,8 @@ describe("LocationResolverService - Reactivity Tests", () => {
mockContainerProps({
markers: [
{
- latitude: dynamic(`${40 + i}`),
- longitude: dynamic("-74")
+ latitude: dynamic.available(`${40 + i}`),
+ longitude: dynamic.available("-74")
} as MarkersType
]
})
diff --git a/packages/pluggableWidgets/maps-web/src/model/services/__tests__/LocationResolver.unit.spec.ts b/packages/pluggableWidgets/maps-web/src/model/services/__tests__/LocationResolver.unit.spec.ts
index 955e49d9a0..87a891cf1d 100644
--- a/packages/pluggableWidgets/maps-web/src/model/services/__tests__/LocationResolver.unit.spec.ts
+++ b/packages/pluggableWidgets/maps-web/src/model/services/__tests__/LocationResolver.unit.spec.ts
@@ -41,9 +41,9 @@ describe("LocationResolverService - Unit Tests", () => {
props: mockContainerProps({
markers: [
{
- latitude: dynamic("40.7128"),
- longitude: dynamic("-74.0060"),
- title: dynamic("NYC")
+ latitude: dynamic.available("40.7128"),
+ longitude: dynamic.available("-74.0060"),
+ title: dynamic.available("NYC")
} as MarkersType
]
}),
@@ -77,8 +77,8 @@ describe("LocationResolverService - Unit Tests", () => {
geodecodeApiKey: "test-api-key",
markers: [
{
- address: dynamic("New York, NY"),
- title: dynamic("NYC")
+ address: dynamic.available("New York, NY"),
+ title: dynamic.available("NYC")
} as MarkersType
]
}),
@@ -158,10 +158,10 @@ describe("LocationResolverService - Unit Tests", () => {
createTestContainer({
props: mockContainerProps({
geodecodeApiKey: "static-key",
- geodecodeApiKeyExp: dynamic("expression-key"),
+ geodecodeApiKeyExp: dynamic.available("expression-key"),
markers: [
{
- address: dynamic("New York, NY")
+ address: dynamic.available("New York, NY")
} as MarkersType
]
}),
@@ -181,7 +181,7 @@ describe("LocationResolverService - Unit Tests", () => {
props: mockContainerProps({
markers: [
{
- address: dynamic("New York, NY")
+ address: dynamic.available("New York, NY")
} as MarkersType
]
}),
@@ -206,8 +206,8 @@ describe("LocationResolverService - Unit Tests", () => {
props: mockContainerProps({
markers: [
{
- latitude: dynamic("40"),
- longitude: dynamic("-74")
+ latitude: dynamic.available("40"),
+ longitude: dynamic.available("-74")
} as MarkersType
]
}),
diff --git a/packages/pluggableWidgets/maps-web/src/utils/__tests__/data.spec.ts b/packages/pluggableWidgets/maps-web/src/utils/__tests__/data.spec.ts
index 060c257156..f7cca7c2e5 100644
--- a/packages/pluggableWidgets/maps-web/src/utils/__tests__/data.spec.ts
+++ b/packages/pluggableWidgets/maps-web/src/utils/__tests__/data.spec.ts
@@ -8,12 +8,12 @@ describe("data.ts - Marker Conversion Functions", () => {
it("should convert marker with all fields present", () => {
const mockAction = jest.fn();
const marker: MarkersType = {
- address: dynamic("123 Main St"),
- latitude: dynamic("40.7128"),
- longitude: dynamic("-74.0060"),
- title: dynamic("New York"),
+ address: dynamic.available("123 Main St"),
+ latitude: dynamic.available("40.7128"),
+ longitude: dynamic.available("-74.0060"),
+ title: dynamic.available("New York"),
onClick: { canExecute: true, isExecuting: false, execute: mockAction },
- customMarker: dynamic({ uri: "marker.png" } as any),
+ customMarker: dynamic.available({ uri: "marker.png" } as any),
locationType: "latlng",
markerStyle: "image"
};
@@ -56,8 +56,8 @@ describe("data.ts - Marker Conversion Functions", () => {
it("should parse numbers with comma as decimal separator", () => {
const marker: MarkersType = {
- latitude: dynamic("40,7128"),
- longitude: dynamic("-74,0060"),
+ latitude: dynamic.available("40,7128"),
+ longitude: dynamic.available("-74,0060"),
locationType: "latlng",
markerStyle: "default"
};
@@ -70,8 +70,8 @@ describe("data.ts - Marker Conversion Functions", () => {
it("should parse numbers with period as decimal separator", () => {
const marker: MarkersType = {
- latitude: dynamic("40.7128"),
- longitude: dynamic("-74.0060"),
+ latitude: dynamic.available("40.7128"),
+ longitude: dynamic.available("-74.0060"),
locationType: "latlng",
markerStyle: "default"
};
@@ -84,9 +84,9 @@ describe("data.ts - Marker Conversion Functions", () => {
it("should handle empty customMarker image", () => {
const marker: MarkersType = {
- latitude: dynamic("40"),
- longitude: dynamic("-74"),
- customMarker: dynamic(undefined as any),
+ latitude: dynamic.available("40"),
+ longitude: dynamic.available("-74"),
+ customMarker: dynamic.unavailable(),
locationType: "latlng",
markerStyle: "image"
};
@@ -382,7 +382,7 @@ describe("data.ts - Marker Conversion Functions", () => {
locationType: "latlng",
latitude: listAttribute(() => "40" as any),
longitude: listAttribute(() => "-74" as any),
- customMarkerDynamic: dynamic({ uri: "custom-marker.png" } as any),
+ customMarkerDynamic: dynamic.available({ uri: "custom-marker.png" } as any),
markerStyleDynamic: "image"
};
diff --git a/packages/pluggableWidgets/pie-doughnut-chart-web/src/__tests__/PieChart.spec.tsx b/packages/pluggableWidgets/pie-doughnut-chart-web/src/__tests__/PieChart.spec.tsx
index 19c17129d6..2d3f0a9f36 100644
--- a/packages/pluggableWidgets/pie-doughnut-chart-web/src/__tests__/PieChart.spec.tsx
+++ b/packages/pluggableWidgets/pie-doughnut-chart-web/src/__tests__/PieChart.spec.tsx
@@ -141,8 +141,8 @@ function setupBasicAttributes(): Partial {
const seriesName = listExp(() => "name");
seriesName.get = jest
.fn()
- .mockReturnValueOnce(dynamic("first series"))
- .mockReturnValueOnce(dynamic("second series"));
+ .mockReturnValueOnce(dynamic.available("first series"))
+ .mockReturnValueOnce(dynamic.available("second series"));
const seriesDataSource = list(2);
@@ -153,7 +153,10 @@ function setupBasicAttributes(): Partial {
.mockReturnValueOnce(new EditableValueBuilder().withValue(new Big(2)).build());
const seriesColorAttribute = listExp(() => "name");
- seriesColorAttribute.get = jest.fn().mockReturnValueOnce(dynamic("red")).mockReturnValueOnce(dynamic("blue"));
+ seriesColorAttribute.get = jest
+ .fn()
+ .mockReturnValueOnce(dynamic.available("red"))
+ .mockReturnValueOnce(dynamic.available("blue"));
const seriesSortAttribute = new ListAttributeValueBuilder().build();
seriesSortAttribute.get = jest
diff --git a/packages/pluggableWidgets/popup-menu-web/package.json b/packages/pluggableWidgets/popup-menu-web/package.json
index c6542b0368..6cc85b8a6a 100644
--- a/packages/pluggableWidgets/popup-menu-web/package.json
+++ b/packages/pluggableWidgets/popup-menu-web/package.json
@@ -54,6 +54,7 @@
"@mendix/run-e2e": "workspace:*",
"@mendix/widget-plugin-hooks": "workspace:*",
"@mendix/widget-plugin-platform": "workspace:*",
+ "@mendix/widget-plugin-test-utils": "workspace:*",
"classnames": "^2.5.1"
}
}
diff --git a/packages/pluggableWidgets/popup-menu-web/src/__tests__/Menu.spec.tsx b/packages/pluggableWidgets/popup-menu-web/src/__tests__/Menu.spec.tsx
index 11dcf579e6..4f9fc315bf 100644
--- a/packages/pluggableWidgets/popup-menu-web/src/__tests__/Menu.spec.tsx
+++ b/packages/pluggableWidgets/popup-menu-web/src/__tests__/Menu.spec.tsx
@@ -1,10 +1,10 @@
import { fireEvent, render, RenderResult } from "@testing-library/react";
import { ValueStatus } from "mendix";
import { createElement } from "react";
+import { actionValue, dynamic } from "@mendix/widget-plugin-test-utils";
import { MenuWithContext as Menu } from "./MenuWithContext";
import { BasicItemsType, CustomItemsType } from "../../typings/PopupMenuProps";
import { MenuProps } from "../components/Menu";
-import { actionValue, dynamicValue } from "../utils/attrValue";
import "@testing-library/jest-dom";
@@ -20,7 +20,7 @@ describe("Menu", () => {
const createPopupMenu = (props: MenuProps): RenderResult => render();
const basicItemProps: BasicItemsType = {
itemType: "item",
- caption: dynamicValue("Caption"),
+ caption: dynamic.available("Caption"),
styleClass: "defaultStyle"
};
const customItemProps: CustomItemsType = { content: createElement("div", null, null) };
@@ -38,7 +38,7 @@ describe("Menu", () => {
position: "bottom",
basicItems: [
basicItemProps,
- { itemType: "divider", caption: dynamicValue("Caption"), styleClass: "defaultStyle" }
+ { itemType: "divider", caption: dynamic.available("Caption"), styleClass: "defaultStyle" }
],
customItems: [customItemProps],
onItemClick: jest.fn(),
@@ -84,7 +84,7 @@ describe("Menu", () => {
...defaultProps,
basicItems: [
basicItem,
- { itemType: "divider", caption: dynamicValue("Caption"), styleClass: "defaultStyle" }
+ { itemType: "divider", caption: dynamic.available("Caption"), styleClass: "defaultStyle" }
]
});
const { container } = popupMenu;
diff --git a/packages/pluggableWidgets/popup-menu-web/src/__tests__/PopupMenu.spec.tsx b/packages/pluggableWidgets/popup-menu-web/src/__tests__/PopupMenu.spec.tsx
index 62807d3b2c..1b3ef09c15 100644
--- a/packages/pluggableWidgets/popup-menu-web/src/__tests__/PopupMenu.spec.tsx
+++ b/packages/pluggableWidgets/popup-menu-web/src/__tests__/PopupMenu.spec.tsx
@@ -1,9 +1,9 @@
import { render, RenderResult } from "@testing-library/react";
import { ValueStatus } from "mendix";
import { createElement } from "react";
+import { dynamic } from "@mendix/widget-plugin-test-utils";
import { BasicItemsType, CustomItemsType, PopupMenuContainerProps } from "../../typings/PopupMenuProps";
import { PopupMenu } from "../components/PopupMenu";
-import { dynamicValue } from "../utils/attrValue";
import "@testing-library/jest-dom";
@@ -13,7 +13,7 @@ describe("Popup Menu", () => {
const createPopupMenu = (props: PopupMenuContainerProps): RenderResult => render();
const basicItemProps: BasicItemsType = {
itemType: "item",
- caption: dynamicValue("Caption"),
+ caption: dynamic.available("Caption"),
styleClass: "defaultStyle"
};
const customItemProps: CustomItemsType = { content: createElement("div", null, null) };
@@ -31,7 +31,7 @@ describe("Popup Menu", () => {
clickCloseOn: "onClickAnywhere",
basicItems: [
basicItemProps,
- { itemType: "divider", caption: dynamicValue("Caption"), styleClass: "defaultStyle" }
+ { itemType: "divider", caption: dynamic.available("Caption"), styleClass: "defaultStyle" }
],
customItems: [customItemProps],
clippingStrategy: "absolute"
diff --git a/packages/pluggableWidgets/popup-menu-web/src/utils/attrValue.ts b/packages/pluggableWidgets/popup-menu-web/src/utils/attrValue.ts
deleted file mode 100644
index 1e999017b1..0000000000
--- a/packages/pluggableWidgets/popup-menu-web/src/utils/attrValue.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-import { ActionValue, DynamicValue, ValueStatus } from "mendix";
-
-export function dynamicValue(value?: T, loading?: boolean): DynamicValue {
- if (loading) {
- return { status: ValueStatus.Loading, value };
- }
- return value !== undefined
- ? { status: ValueStatus.Available, value }
- : { status: ValueStatus.Unavailable, value: undefined };
-}
-
-export function actionValue(canExecute = true, isExecuting = false): ActionValue {
- return { canExecute, isExecuting, execute: jest.fn() };
-}
diff --git a/packages/pluggableWidgets/signature-web/src/__tests__/Signature.spec.tsx b/packages/pluggableWidgets/signature-web/src/__tests__/Signature.spec.tsx
index 3d653cb316..22154a4ca0 100644
--- a/packages/pluggableWidgets/signature-web/src/__tests__/Signature.spec.tsx
+++ b/packages/pluggableWidgets/signature-web/src/__tests__/Signature.spec.tsx
@@ -1,8 +1,8 @@
import "@testing-library/jest-dom";
import { render, screen } from "@testing-library/react";
import { ReactElement } from "react";
-import { SignatureContainerProps } from "../../typings/SignatureProps";
import { dynamic } from "@mendix/widget-plugin-test-utils";
+import { SignatureContainerProps } from "../../typings/SignatureProps";
import Signature from "../Signature";
const mockSignatureComponent = jest.fn((_props: unknown) => );
@@ -38,7 +38,7 @@ describe("Signature", () => {
gridCellHeight: 20,
gridCellWidth: 20,
gridBorderWidth: 1,
- ariaRequired: dynamic(false)
+ ariaRequired: dynamic.available(false)
};
beforeEach(() => {
diff --git a/packages/pluggableWidgets/time-series-chart-web/src/__test__/TimeSeries.spec.tsx b/packages/pluggableWidgets/time-series-chart-web/src/__test__/TimeSeries.spec.tsx
index c8db2d37f8..3be62ac2ae 100644
--- a/packages/pluggableWidgets/time-series-chart-web/src/__test__/TimeSeries.spec.tsx
+++ b/packages/pluggableWidgets/time-series-chart-web/src/__test__/TimeSeries.spec.tsx
@@ -68,7 +68,7 @@ describe("The TimeSeries widget", () => {
});
it("sets the line color on the data series based on the lineColor value", () => {
- renderTimeSeries([{ lineColor: dynamic("red") }, { lineColor: undefined }]);
+ renderTimeSeries([{ lineColor: dynamic.available("red") }, { lineColor: undefined }]);
const mockCalls = (ChartWidget as jest.Mock).mock.calls;
const lastCallProps = mockCalls[mockCalls.length - 1][0];
@@ -77,7 +77,7 @@ describe("The TimeSeries widget", () => {
});
it("sets the marker color on the data series based on the markerColor value", () => {
- renderTimeSeries([{ markerColor: undefined }, { markerColor: dynamic("blue") }]);
+ renderTimeSeries([{ markerColor: undefined }, { markerColor: dynamic.available("blue") }]);
const mockCalls = (ChartWidget as jest.Mock).mock.calls;
const lastCallProps = mockCalls[mockCalls.length - 1][0];
@@ -100,7 +100,7 @@ describe("The TimeSeries widget", () => {
});
it("sets the area fill color on the data series based on fillColor", () => {
- renderTimeSeries([{ fillColor: dynamic("red") }]);
+ renderTimeSeries([{ fillColor: dynamic.available("red") }]);
const mockCalls = (ChartWidget as jest.Mock).mock.calls;
const lastCallProps = mockCalls[mockCalls.length - 1][0];
diff --git a/packages/pluggableWidgets/tree-node-web/src/components/v2/hooks/__tests__/useIncrementalTreeData.spec.ts b/packages/pluggableWidgets/tree-node-web/src/components/v2/hooks/__tests__/useIncrementalTreeData.spec.ts
index 3563443eb4..598aeff794 100644
--- a/packages/pluggableWidgets/tree-node-web/src/components/v2/hooks/__tests__/useIncrementalTreeData.spec.ts
+++ b/packages/pluggableWidgets/tree-node-web/src/components/v2/hooks/__tests__/useIncrementalTreeData.spec.ts
@@ -12,12 +12,10 @@ function makeConfig(overrides: Partial = {}): TreeConfigRef {
return {
headerType: "text",
headerCaption: {
- get: jest.fn((item: ObjectItem) => dynamic(String(item.id)))
+ get: jest.fn((item: ObjectItem) => dynamic.available(String(item.id)))
} as any,
headerContent: undefined,
- parentAssociation: listReference(b =>
- b.withGet((_item: ObjectItem) => dynamic(undefined as unknown as ObjectItem)).build()
- ),
+ parentAssociation: listReference(b => b.withGet((_item: ObjectItem) => dynamic.unavailable()).build()),
startExpanded: false,
...overrides
};
@@ -30,14 +28,14 @@ function makeConfigWithParentMap(
return {
headerType: "text",
headerCaption: {
- get: jest.fn((item: ObjectItem) => dynamic(String(item.id)))
+ get: jest.fn((item: ObjectItem) => dynamic.available(String(item.id)))
} as any,
headerContent: undefined,
parentAssociation: listReference(b =>
b
.withGet((item: ObjectItem) => {
const parentId = parentMap[String(item.id)];
- return parentId ? dynamic(makeItem(parentId)) : dynamic(undefined as unknown as ObjectItem);
+ return parentId ? dynamic.available(makeItem(parentId)) : dynamic.unavailable();
})
.build()
),
diff --git a/packages/shared/charts/src/hooks/__tests__/usePlotChartDataSeries.spec.ts b/packages/shared/charts/src/hooks/__tests__/usePlotChartDataSeries.spec.ts
index 4ff58aa2bd..f91155ae7a 100644
--- a/packages/shared/charts/src/hooks/__tests__/usePlotChartDataSeries.spec.ts
+++ b/packages/shared/charts/src/hooks/__tests__/usePlotChartDataSeries.spec.ts
@@ -1,6 +1,6 @@
import { renderHook } from "@testing-library/react";
import { PlotDataSeries, SeriesMapper, usePlotChartDataSeries } from "../usePlotChartDataSeries";
-import { dynamicValue, EditableValueBuilder, list, ListAttributeValueBuilder } from "@mendix/widget-plugin-test-utils";
+import { dynamic, EditableValueBuilder, list, ListAttributeValueBuilder } from "@mendix/widget-plugin-test-utils";
import { ListActionValue, ListAttributeValue, ListExpressionValue, ListValue } from "mendix";
function axisAttr(): ListAttributeValue {
@@ -33,7 +33,7 @@ function singleData(): PlotDataSeries {
function multiData(
params: { n: number; groups: string[]; ds?: ListValue } = { n: 12, groups: ["alpha", "beta"] }
): PlotDataSeries {
- const x = { get: () => dynamicValue(Math.random().toString()) } as unknown as ListExpressionValue;
+ const x = { get: () => dynamic.available(Math.random().toString()) } as unknown as ListExpressionValue;
return {
dataSet: "dynamic",
dynamicDataSource: params.ds ?? list(params.n),
diff --git a/packages/shared/widget-plugin-component-kit/src/__tests__/__snapshots__/ThreeStateCheckBox.spec.tsx.snap b/packages/shared/widget-plugin-component-kit/src/__tests__/__snapshots__/ThreeStateCheckBox.spec.tsx.snap
index 4f91b88801..dcce2c0892 100644
--- a/packages/shared/widget-plugin-component-kit/src/__tests__/__snapshots__/ThreeStateCheckBox.spec.tsx.snap
+++ b/packages/shared/widget-plugin-component-kit/src/__tests__/__snapshots__/ThreeStateCheckBox.spec.tsx.snap
@@ -1,4 +1,4 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`ThreeStateCheckBox matches snapshot when value is 'all' 1`] = `
diff --git a/packages/shared/widget-plugin-test-utils/__tests__/filters/__snapshots__/builders.test.ts.snap b/packages/shared/widget-plugin-test-utils/__tests__/filters/__snapshots__/builders.test.ts.snap
index b0b9762e95..4e2233e55d 100644
--- a/packages/shared/widget-plugin-test-utils/__tests__/filters/__snapshots__/builders.test.ts.snap
+++ b/packages/shared/widget-plugin-test-utils/__tests__/filters/__snapshots__/builders.test.ts.snap
@@ -1,4 +1,4 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
+// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`mendix/filters/builders mock nested condition case 1 1`] = `
{
diff --git a/packages/shared/widget-plugin-test-utils/__tests__/primitives.test.ts b/packages/shared/widget-plugin-test-utils/__tests__/primitives.test.ts
index 43699cb692..cc462dd71d 100644
--- a/packages/shared/widget-plugin-test-utils/__tests__/primitives.test.ts
+++ b/packages/shared/widget-plugin-test-utils/__tests__/primitives.test.ts
@@ -30,24 +30,37 @@ describe("attrId", () => {
});
describe("dynamic", () => {
- it("returns dynamic value mock", () => {
- expect(dynamic("someString")).toMatchObject({
- status: Status.Available,
- value: "someString"
+ describe("dynamic.available", () => {
+ it("returns dynamic value mock", () => {
+ expect(dynamic.available("someString")).toMatchObject({
+ status: Status.Available,
+ value: "someString"
+ });
});
});
- it("returns 'unavailable' by default", () => {
- expect(dynamic()).toMatchObject({
- status: Status.Unavailable,
- value: undefined
+ describe("dynamic.loading", () => {
+ it("returns loading status with a value", () => {
+ expect(dynamic.loading("someString")).toMatchObject({
+ status: Status.Loading,
+ value: "someString"
+ });
+ });
+
+ it("returns loading status without a value", () => {
+ expect(dynamic.loading()).toMatchObject({
+ status: Status.Loading,
+ value: undefined
+ });
});
});
- it("pass loading status", () => {
- expect(dynamic("someString", true)).toMatchObject({
- status: Status.Loading,
- value: "someString"
+ describe("dynamic.unavailable", () => {
+ it("returns unavailable status", () => {
+ expect(dynamic.unavailable()).toMatchObject({
+ status: Status.Unavailable,
+ value: undefined
+ });
});
});
});
diff --git a/packages/shared/widget-plugin-test-utils/src/builders/ListReferenceSetValueBuilder.ts b/packages/shared/widget-plugin-test-utils/src/builders/ListReferenceSetValueBuilder.ts
index 46d93a12ed..9dbbf4691f 100644
--- a/packages/shared/widget-plugin-test-utils/src/builders/ListReferenceSetValueBuilder.ts
+++ b/packages/shared/widget-plugin-test-utils/src/builders/ListReferenceSetValueBuilder.ts
@@ -11,7 +11,7 @@ export class ListReferenceSetValueBuilder {
type: "ReferenceSet",
id: `listRefSet_${nanoid()}` as any,
filterable: true,
- get: jest.fn((_: ObjectItem) => dynamic(objArray(1)))
+ get: jest.fn((_: ObjectItem) => dynamic.available(objArray(1)))
};
}
diff --git a/packages/shared/widget-plugin-test-utils/src/builders/ListReferenceValueBuilder.ts b/packages/shared/widget-plugin-test-utils/src/builders/ListReferenceValueBuilder.ts
index 72d6feab19..b502d08dc2 100644
--- a/packages/shared/widget-plugin-test-utils/src/builders/ListReferenceValueBuilder.ts
+++ b/packages/shared/widget-plugin-test-utils/src/builders/ListReferenceValueBuilder.ts
@@ -10,7 +10,7 @@ export class ListReferenceValueBuilder {
type: "Reference",
id: `listRef_${nanoid()}` as any,
filterable: true,
- get: jest.fn((_: ObjectItem) => dynamic(obj()))
+ get: jest.fn((_: ObjectItem) => dynamic.available(obj()))
};
}
diff --git a/packages/shared/widget-plugin-test-utils/src/functions/listExpression.ts b/packages/shared/widget-plugin-test-utils/src/functions/listExpression.ts
index f494ebd0ec..36bc0d8ccd 100644
--- a/packages/shared/widget-plugin-test-utils/src/functions/listExpression.ts
+++ b/packages/shared/widget-plugin-test-utils/src/functions/listExpression.ts
@@ -8,7 +8,7 @@ import { dynamic } from "../primitives/dynamic";
export function listExpression(
get: (item: ObjectItem) => T
): ListExpressionValue {
- return { get: (item: ObjectItem) => dynamic(get(item)) };
+ return { get: (item: ObjectItem) => dynamic.available(get(item)) };
}
/** @deprecated Renamed to `listExpression` */
diff --git a/packages/shared/widget-plugin-test-utils/src/primitives/dynamic.ts b/packages/shared/widget-plugin-test-utils/src/primitives/dynamic.ts
index d808cf6297..eb1ad937c0 100644
--- a/packages/shared/widget-plugin-test-utils/src/primitives/dynamic.ts
+++ b/packages/shared/widget-plugin-test-utils/src/primitives/dynamic.ts
@@ -1,12 +1,20 @@
import { DynamicValue } from "mendix";
import { Status } from "../constants.js";
-export function dynamic(value?: T, loading = false): DynamicValue {
- if (value === undefined) {
- return { status: Status.Unavailable, value: undefined };
- }
- return { status: loading ? Status.Loading : Status.Available, value };
+function available(value: T): DynamicValue {
+ return { status: Status.Available, value };
}
-/** @deprecated renamed to {@link dynamic} */
-export const dynamicValue = dynamic;
+function loading(value?: T): DynamicValue {
+ return { status: Status.Loading, value };
+}
+
+function unavailable(): DynamicValue {
+ return { status: Status.Unavailable, value: undefined };
+}
+
+export const dynamic = {
+ available,
+ loading,
+ unavailable
+};
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index f632d8ab75..607db78a3f 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -1988,6 +1988,9 @@ importers:
'@mendix/widget-plugin-platform':
specifier: workspace:*
version: link:../../shared/widget-plugin-platform
+ '@mendix/widget-plugin-test-utils':
+ specifier: workspace:*
+ version: link:../../shared/widget-plugin-test-utils
classnames:
specifier: ^2.5.1
version: 2.5.1