diff --git a/pesde.lock b/pesde.lock index d7facd3e..dc0ec79b 100644 --- a/pesde.lock +++ b/pesde.lock @@ -18,14 +18,14 @@ frktest = [{ name = "itsfrank/frktest", version = "^0.0.2", index = "https://git luau-lsp = [{ name = "pesde/luau_lsp", version = "=1.39.2", index = "https://github.com/pesde-pkg/index", target = "lune" }, "dev"] stylua = [{ name = "pesde/stylua", version = "=2.0.2", index = "https://github.com/pesde-pkg/index", target = "lune" }, "dev"] -[graph."beastslash/ijw@1.1.3 roblox"] -direct = ["ijw", { name = "beastslash/ijw", version = "^1.1.3", index = "default" }, "dev"] +[graph."beastslash/ijw@2.0.0 roblox"] +direct = ["ijw", { name = "beastslash/ijw", version = "^2.0.0", index = "default" }, "dev"] -[graph."beastslash/ijw@1.1.3 roblox".pkg_ref] +[graph."beastslash/ijw@2.0.0 roblox".pkg_ref] ref_ty = "pesde" index_url = "https://github.com/pesde-pkg/index" -[graph."beastslash/ijw@1.1.3 roblox".pkg_ref.dependencies] +[graph."beastslash/ijw@2.0.0 roblox".pkg_ref.dependencies] luau_lsp = [{ name = "pesde/luau_lsp", version = "^1.48.0", index = "https://github.com/pesde-pkg/index", target = "lune" }, "dev"] rojo = [{ name = "pesde/rojo", version = "^7.5.1", index = "https://github.com/pesde-pkg/index", target = "lune" }, "dev"] scripts = [{ name = "pesde/scripts_rojo", version = "^0.1.0", index = "https://github.com/pesde-pkg/index", target = "lune" }, "dev"] diff --git a/src/DialogueEditor/components/Button/init.luau b/src/DialogueEditor/components/Button/init.luau index 3097b75b..f327740b 100644 --- a/src/DialogueEditor/components/Button/init.luau +++ b/src/DialogueEditor/components/Button/init.luau @@ -3,6 +3,7 @@ local root = script.Parent.Parent.Parent; local React = require(root.roblox_packages.react); local useStudioColors = require(root.DialogueEditor.hooks.useStudioColors); +local VirtualService = require(root.VirtualService); export type ButtonProperties = { text: string; @@ -20,6 +21,30 @@ local function Button(properties: ButtonProperties) local text = properties.text; local isDisabled = properties.isDisabled; local onClick = properties.onClick; + local buttonRef = React.useRef(nil); + + React.useEffect(function() + + local button = buttonRef.current; + assert(button, "Button reference is nil."); + + local activatedConnection = VirtualService.events.GuiButton.Activated:getSignal(button):Connect(function(self) + + if not isDisabled then + + onClick(); + + end; + + end); + + return function() + + activatedConnection:Disconnect(); + + end; + + end, {onClick}); return React.createElement("TextButton", { AutomaticSize = Enum.AutomaticSize.XY; @@ -27,13 +52,10 @@ local function Button(properties: ButtonProperties) Text = ""; LayoutOrder = layoutOrder; Size = UDim2.fromOffset(0, 30); - [React.Event.Activated] = function() + ref = buttonRef; + [React.Event.Activated] = function(self) - if not isDisabled then - - onClick(); - - end; + VirtualService.events.GuiButton.Activated:fireEvent(self); end; }, { diff --git a/src/DialogueEditor/components/Explorer/components/Preview/components/DialogueOptions/DialogueOptions.test.luau b/src/DialogueEditor/components/Explorer/components/Preview/components/DialogueOptions/DialogueOptions.test.luau new file mode 100644 index 00000000..f741d2f6 --- /dev/null +++ b/src/DialogueEditor/components/Explorer/components/Preview/components/DialogueOptions/DialogueOptions.test.luau @@ -0,0 +1,167 @@ +--!strict + +local root = script.Parent.Parent.Parent.Parent.Parent.Parent.Parent.Parent; +local DialogueOptions = require(script.Parent); +local VirtualService = require(root.VirtualService); +local React = require(root.roblox_packages.react); +local ReactErrorBoundary = require(root.roblox_packages.ReactErrorBoundary); +local ErrorBoundary = ReactErrorBoundary.ErrorBoundary; +local ReactRoblox = require(root.roblox_packages["react-roblox"]); +local IJW = require(root.roblox_packages.ijw); +local expect = IJW.expect; +local describe = IJW.describe; +local it = IJW.it; + +local screenGui: ScreenGui?; +local reactRoot: ReactRoblox.RootType?; +local propagatedErrorMessage; +local eventConnection: RBXScriptConnection?; + +return { + + describe("DialogueOptions", function() + + local function MockComponent(properties: any) + + local selectedScript = properties.selectedScript; + local onErrored = properties.onErrored or function() end; + local onRendered = properties.onRendered or function() end; + + React.useEffect(function() + + onRendered(); + + end, {onRendered}); + + return React.createElement(ErrorBoundary, { + FallbackComponent = React.Fragment; + onError = onErrored; + }, { + React.createElement(DialogueOptions, { + selectedScript = selectedScript; + plugin = VirtualService.mocks.globals.plugin; + selectedDialogueType = selectedScript:GetAttribute("DialogueType") or "Conversation"; + layoutOrder = 1; + }) + }); + + end; + + local function verifyReactStatus() + + if propagatedErrorMessage then + + error(propagatedErrorMessage); + + end; + + end; + + local function createDialogueScript(name: string) + + local dialogueScript = Instance.new("ModuleScript"); + dialogueScript:AddTag("DialogueMakerConversationScript"); + return dialogueScript; + + end; + + local function render(): ModuleScript + + assert(reactRoot, "React root should be initialized before running tests."); + + local selectedScript = createDialogueScript("TestDialogueScript"); + local didRender = false; + local element = React.createElement(MockComponent, { + selectedScript = selectedScript; + onErrored = function(errorMessage) + + propagatedErrorMessage = errorMessage; + + end; + onRendered = function() + + didRender = true; + + end; + }); + + reactRoot:render(element); + repeat task.wait() until didRender or propagatedErrorMessage; + verifyReactStatus(); + + return selectedScript; + + end; + + return { + + it("can delete selected script", function() + + expect(function() + + local selectedScript = render(); + local testFolder = Instance.new("Folder"); + selectedScript.Parent = testFolder; + + assert(screenGui, "ScreenGui should be initialized before running tests."); + local dialogueOptions = screenGui:FindFirstChildOfClass("Frame"); + assert(dialogueOptions, "DialogueOptions should be rendered."); + + local deleteButton = dialogueOptions:FindFirstChild("DeleteButton"); + assert(deleteButton and deleteButton:IsA("TextButton"), "Delete button should be present in the DialogueOptions."); + + local didChangeParent = false; + eventConnection = selectedScript:GetPropertyChangedSignal("Parent"):Once(function() + + didChangeParent = true; + + end); + VirtualService.events.GuiButton.Activated:fireEvent(deleteButton); + repeat task.wait() until didChangeParent or propagatedErrorMessage; + verifyReactStatus(); + expect(selectedScript.Parent).toBe(nil); + + end).toFinishBeforeSeconds(1); + + end); + + } + + end, { + beforeEach = function() + + local newScreenGui = Instance.new("ScreenGui"); + screenGui = newScreenGui; + reactRoot = ReactRoblox.createRoot(newScreenGui); + VirtualService.mocks.isEnabled = true; + + end; + afterEach = function() + + if reactRoot then + + reactRoot:unmount(); + reactRoot = nil; + + end; + + if screenGui then + + screenGui:Destroy(); + screenGui = nil; + + end; + + if eventConnection then + + eventConnection:Disconnect(); + eventConnection = nil; + + end; + + propagatedErrorMessage = nil; + VirtualService.mocks.isEnabled = false; + + end; + }) +}; \ No newline at end of file diff --git a/src/DialogueEditor/components/Explorer/components/Preview/components/DialogueOptions/init.luau b/src/DialogueEditor/components/Explorer/components/Preview/components/DialogueOptions/init.luau index 4a5ccb8d..622bda6b 100644 --- a/src/DialogueEditor/components/Explorer/components/Preview/components/DialogueOptions/init.luau +++ b/src/DialogueEditor/components/Explorer/components/Preview/components/DialogueOptions/init.luau @@ -10,6 +10,7 @@ local DropdownOption = require(root.DialogueEditor.components.DropdownOption); local useStudioColors = require(root.DialogueEditor.hooks.useStudioColors); local useDialogueScriptType = require(root.DialogueEditor.hooks.useDialogueScriptType); local useChangeHistory = require(root.DialogueEditor.hooks.useChangeHistory); +local VirtualService = require(root.VirtualService); type DialogueScriptType = useDialogueScriptType.DialogueScriptType; @@ -22,6 +23,8 @@ export type DialogueOptionsProperties = { local function DialogueOptions(properties: DialogueOptionsProperties) + Selection = if VirtualService.mocks.isEnabled then VirtualService.mocks.services.Selection else Selection; + local selectedScript = properties.selectedScript; local selectedDialogueType = properties.selectedDialogueType; local layoutOrder = properties.layoutOrder;