Hi @BrianEkins , thank you very much for the detailed answer and the additional idea.
It makes sense to me add unit tests right in the add-in code. It is usually a common practice (and makes the developer's life easier) when you develop a individual library/application, or an add-in/plug-in for a software suite.
It feels like the 2nd option might be applied through a script, i.e. create the script through the "Scripts and Add-Ins" menu option and add the testing code (like you described or in various different ways) to the newly created script. Whenever the developers need testing, they could run the script and see the outcome.
Perhaps the 3rd option might also be applied through a script, and to be honest, I like the idea.
In addition, I have been exploring what hidden capabilities Fusion 360 has and the simplest method would be calling the main executable with "--help" argument to see if it shows anything useful. Actually, I can get the following output on MacOS Ventura with the latest Fusion 360 as of today.
➜ MacOS ./Autodesk\ Fusion\ 360 --help
Following are the existing command line options in the system (case in-sensitive):
--help, -? Display the help information.
--showInternal Display internal command line actions to the user.
--nologo Disable splash screen
--exit Shutdown the application before loading Addins
--exitAfterAddIn Shutdown the application after loading Addins
--safeMode Run in safe mode that disables automatic script loading and certain optimization
--serviceUtil Run the Fusion service utility
--activateTestingContext Activate testing context
--standaloneNTestStartFusion The flag represent fusion is started up by standalone NTest
--AutoCAD Show return to AutoCAD button
--Inventor Show return to Inventor button
--TestingDashboard Set testing flag to disable dialogs to support automation of dashboard JS tests
--ClearUserCache Try to delete Fusion user's cloud cache folders when we are online.
--offlineStart Start from offline
--script, -s <Script> Execute the given script after loading addins
--execute, -e <TextCommand> Execute the given text command after loading addins
--enable <Addin1_AppName Addin2_AppName...> Enable the given addins (in double-quotes)
--disable <Addin1_AppName Addin2_AppName...> Disable the given addins (in double-quotes)
--print Not implemented yet
--log <Log file> Save command-line output into a log file
--Diagnostic, -d Dump out user's diagnostics data to a zip file via command-line
--autologin username,password
--autoregister firstname,lastname,email,password
--fullTest [Result file] Run full regression test after UI loaded
--perfTest <Baseline> [TestCase|TranscriptFileOrDir] [/log <Result file>] Run performance tests after UI loaded, and exit the application after running the tests. Either relative path to "Performance" folder or a full path is acceptable in Baseline and TranscriptFileOrDir
It looks like there are some ways to run scripts and text commands through the command-line interface and a little bit more that we can do too. I haven't tested if they actually work, but I would think they should.
Regarding running Fusion 360 on a headless server, I was actually thinking positively before your answer due to how the coding examples are structured on Fusion 360 documentation. For instance, it is very common to see a structure in a Fusion 360 example like this:
import adsk, adsk.core
app = adsk.core.Application.get()
ui = app.userInterface
# Some script body here
try:
# Do something
except:
# Is there a state where ui is not available?
if ui:
ui.messageBox("Error occurred")
# Log to the console or file
app.log("Error occurred with details", adsk.core.LogLevels.ErrorLogLevel, adsk.core.LogTypes.ConsoleLogType)
I always thought that checking the availability of the the "ui" object was mainly to understand whether Fusion 360 started with a GUI or not. For sure, unavailability of the "ui" object might happen due to various reasons (which are mainly fixable), but it always felt like there might be a non-UI way to run it. I guess I understood that part a bit differently as you said, it wasn't intended to run this way.