Fluxtester Recipe Book
Table of Contents
Test Structure & Attributes
Basic Test Fixture Template
[TestFixture (ID, "Display Name", Module = "ModuleName", Subsystem = "SubsystemName")]
internal class TestClassName {
const string testMachineID = "97";
[FixtureInitialize]
public void Init () {
// Setup code - runs once before all tests
Utils.ConfigureMachine (testMachineID);
}
[FixtureCleanUp]
public void CleanUp () {
// Cleanup code - runs once after all tests
Utils.UninstallMachine (testMachineID);
}
[TestInitialize]
void Setup () {
// Runs before each test
}
[TestCleanUp]
void TearDown () {
// Runs after each test
}
[Test (ID, "Test Description", Type = TestType.Functional)]
public void Test_MethodName () {
// Test implementation
}
}
Test Attributes
// Test Type Options
Type = TestType.Functional
Type = TestType.Smoke
Type = TestType.Other
Type = TestType.None
Type = TestType.Smoke | TestType.Functional // Multiple types
// Test ID Assignment (Per Developer)
// IDs should be unique per developer branch
File Operations
Opening Files
// Open a part/drawing file
Utils.OpenFile (Utils.tData + "123.fx");
Utils.OpenFile (Utils.tData + "folder/filename.ext");
// Open job or layout files
Utils.OpenJobOrLayout (Path.Combine (sCutFilesPath, filename));
// Open specific file types (Bend, Assembly, etc.)
Utils.OpenFile (tData + "bendtooling/C16922.dxf");
Utils.OpenFile (tData + "assem1.sldasm");
Closing Files & Parts
// Close current part (with or without saving)
Utils.ClosePart (true); // Close with save
Utils.ClosePart (false); // Close without save
// Close Flux application entirely
Utils.CloseFlux ();
Utils.ForceCloseFlux (); // Force close if needed
Temporary File Management
// Create/clear temp directory
Utils.FlushTempPath ();
// Access temp paths
Utils.tempPath // e.g., "c:/programdata/metamation/temp/"
Utils.tempTxtFile = Path.Combine (tempPath, "temp.txt");
Utils.tempPath + "test.png"
// Wait for file creation
Utils.WaitForFileExists ();
// Delete specific temp files
foreach (var file in Directory.GetFiles (Utils.tempPath)) {
if (file.Contains (".txt")) File.Delete (file);
}
Test Data Access
// Path constants
Utils.tData // Test data directory
Utils.resources // Resources directory
Utils.fluxPath // Flux executable path
Utils.fluxDataPath // Flux application data
// Build paths
Utils.tData + "123.fx"
Utils.tData + "InnerContour.fx"
Utils.tData + "Test_C150616/test_normalProfile.txt"
$"{Utils.tData}Test_{folder}/{filename}.txt"
Keyboard & Input Commands
Key Press Patterns
// Single character keystrokes
Utils.Type ('l'); // Navigate to laser tooling
Utils.Type ('k'); // Laser CAM settings
Utils.Type ('b'); // Bend operations
Utils.Type ('t'); // Settings
Utils.Type ('a'); // Layout settings
Utils.Type ('r'); // Recompute/Refresh
Utils.Type ('2'); // Select options
Utils.Type ('3'); // 3D view
Utils.Type ('w'); // Window/workspace operations
Utils.Type ('s'); // Select/settings
Utils.Type ('x'); // Explode components
// Key combinations
Utils.Type (Utils.KeyShort.ESC); // Escape key
Utils.Type (Utils.KeyShort.ENTER); // Enter/Return
Utils.Type (Utils.KeyShort.TAB); // Tab key
// String input
Utils.Type ("lta"); // Multiple keys in sequence
Utils.Type ("w");
Utils.Type ("s");
Utils.Type ("2");
Utils.Type ("l");
KeyShort Enum Values
using static FluxTester.Utils.KeyShort;
// Common key shortcuts
ESC // Escape
ENTER // Enter
TAB // Tab
LBUTTON // Left mouse button
// (See Utils.cs KeyShort enum for full list)
Mouse Operations
// Click at specific coordinates
Utils.MouseClick (Utils.MeasurePtToPixel (new (153.946, 91.549, 0)));
// Drag and drop
Utils.DragAndDrop (startPoint, endPoint);
// Zoom scene
Utils.ZoomScene (0, 0, 0, 0.5); // Zoom out
Utils.ZoomScene (0, 0, 0, 2.0); // Zoom in
// Get clickable point
var clickablePoint = scrollBar.GetClickablePoint ();
UI Automation Patterns
Finding UI Elements
// Find by automation ID
Utils.MainWin.FindFirstChild ("FXMainWin");
Utils.MainWin.FindFirstChild ("DocsPanel");
Utils.MainWin.FindFirstChild ("CmdBar");
Utils.MainWin.FindFirstChild ("Glob");
// Find by name
Utils.MainWin.FindFirstDescendant (e => e.ByName ("Laser Cut"));
Utils.MainWin.FindFirstDescendant (a => a.ByName ("Reverse"));
Utils.MainWin.FindFirstDescendant (a => a.ByName ("Contour"));
// Find by class name
Utils.MainWin.FindFirstDescendant (e => e.ByClassName ("TextBox"));
Utils.MainWin.FindFirstDescendant (a => a.ByClassName ("ComboBox"));
Utils.MainWin.FindFirstDescendant (a => a.ByClassName ("CheckBox"));
// Find by control type
Utils.MainWin.FindFirstChild (e => e.ByControlType (FlaUI.Core.Definitions.ControlType.Edit));
Utils.MainWin.FindFirstDescendant (e => e.ByControlType (ControlType.Pane));
// Complex queries with AND/OR
Utils.MainWin.FindFirstDescendant (a => a.ByName ("Laser CAM").And (a.ByClassName ("TextBlock")));
Utils.MainWin.FindFirstDescendant (a => a.ByName ("mm").Or (a.ByName ("inch")));
// Find child at index
Utils.MainWin.FindChildAt (0);
settings.FindChildAt (2);
// Find all descendants/children
var descendants = element.FindAllDescendants ();
var children = element.FindAllChildren ();
var textBoxes = element.FindAllChildren (a => a.ByClassName ("TextBox"));
Interacting with Controls
TextBox Operations
// Set text value
var appAngle = g.FindFirstChild ("AppAngle").AsTextBox ();
appAngle.Text = "90";
g.FindFirstChild ("EscLength").AsTextBox ().Text = "5";
g.FindFirstChild ("EscRadius").AsTextBox ().Text = "10";
g.FindFirstChild ("EscAngle").AsTextBox ().Text = "45";
// Multi-step textbox update
setting.FindAllChildren (c => c.ByClassName ("TextBox"))[1].AsTextBox ().Text = "5";
setting.FindAllChildren (c => c.ByClassName ("TextBox"))[4].AsTextBox ().Text = "25";
setting.FindAllChildren (c => c.ByClassName ("TextBox"))[5].AsTextBox ().Text = "25";
ComboBox Operations
// Select from dropdown
var comboBox = g.FindFirstChild (a => a.ByClassName ("ComboBox")).AsComboBox ();
comboBox.Select ("Large");
comboBox.Collapse ();
// Multiple selections with loop
string[] options = { "Small", "Medium", "Large", "Mark", "Vaporize", "Dot mark" };
foreach (var option in options) {
comboBox.Select (option);
// Perform validation
}
// Get selected item
var selectedItem = comboBox.SelectedItem.Name;
Assert.AreEqual (selectedItem, "Footprint");
CheckBox Operations
// Toggle checkbox
var dimpleCheckBox = g.FindFirstChild (a => a.ByAutomationId ("Dimple").And (a.ByClassName ("CheckBox"))).AsCheckBox ();
dimpleCheckBox.ToggleState = ToggleState.On;
dimpleCheckBox.ToggleState = ToggleState.Off;
// Click checkbox
g.FindFirstChild (a => a.ByName ("Layer")).Click ();
Button Operations
// Click buttons
LaserCutGlob (fxFile).FindFirstDescendant (a => a.ByName ("Reverse")).Click ();
g.FindFirstDescendant (a => a.ByName ("Add")).Click ();
g.FindFirstDescendant (a => a.ByName ("Remove All")).Click ();
g.FindFirstDescendant (a => a.ByName ("Auto compute")).Click ();
// Click with assertion
Assert.IsNotNull (ToPointOperationButton, "Button not found");
ToPointOperationButton.Click ();
Window Management
// Wait for dialog/glob
var g = Utils.WaitForGlob ();
Assert.IsNotNull (g, "Laser Cut glob did not open");
// Close window
glob.AsWindow ().Close ();
// Check if element exists
var element = Utils.MainWin.FindFirstDescendant (e => e.ByName ("Laser Cut"));
Assert.True (element is null); // Element should not exist
// Use FindElement with retry
Utils.FindElement (() => Utils.MainWin.FindFirstChild ("CmdBar"));
Utils.FindElement (() => Utils.MainWin.FindFirstChild ("DocsPanel").FindFirstChild (a => a.ByName (file)));
Glob (Modal Dialog) Pattern
// Open laser cut editing dialog
var g = LaserCutGlob (fxFile);
// Interact with glob elements
g.FindFirstChild (a => a.ByName ("Contour")).Click ();
g.FindFirstChild ("AppLength").AsTextBox ().Text = "5";
// Close glob
Utils.Type (ESC);
// Verify glob state
Assert.IsNotNull (g, "Glob did not open");
Assert.True (g.FindFirstDescendant (a => a.ByName ("Laser Cut")) is null);
Assertions & Validations
Element Assertions
// Null/Not null checks
Assert.IsNotNull (element, "Element not found message");
Assert.True (Utils.MainWin.FindFirstDescendant (e => e.ByName ("Laser Cut")) is null);
// Text equality
Assert.AreEqual (actualValue, expectedValue);
Assert.AreEqual (selectedItem.Name, "Footprint");
// Boolean assertions
Assert.True (condition, "Message if false");
Assert.False (Utils.FluxCrashed ());
// Collection assertions
Assert.True (comboBox.Items.Any (e => e.Text = process));
File Assertions
// File exists
Assert.True (File.Exists (Utils.tempPath + "importvacuumgripper.fxresp"));
// Text file comparison
Assert.AreTextFilesEqual (expectedPath, actualPath);
Assert.AreTextEqual (expectedPath, actualContent);
// Binary file comparison
Assert.AreBinaryFilesEqual (expectedPath, actualPath);
// Bitmap comparison
Assert.AreBitmapsEqual (expectedPath, actualPath, 95); // 95% tolerance
File Content Validation
// Read and check file content
var lines = File.ReadAllLines (Utils.tempPath + "response.fxresp");
Assert.True (lines[2] = "Completed=1");
// Check for specific text
var content = File.ReadAllText (Utils.tempPath + "temp.txt");
bool hasInvalidData = content.Contains ("Invalid bend data. Bend lines could not be marked.");
Assert.True (process != "None" ? hasInvalidData : !hasInvalidData);
Test-Specific Utilities
Laser Cutting Utilities
LaserCutGlob Helper
// Open laser cut dialog with predefined file
var g = LaserCutGlob (fxFile); // "123.fx"
var g = LaserCutGlob (fxFileWithInnerContour); // "InnerContour.fx"
var g = LaserCutGlob (fxFileWithsmallcircle); // "smallcircle.fx"
// Open with custom coordinates
var g = LaserCutGlob (x: 50.15, y: 46.54);
// Open with special parameters
var g = LaserCutGlob (partFileName: "file.fx", bevel: true, openPoly: false);
// Auto-expands: Approach, Withdrawal, Microjoint, Advanced sections
Cutting Type Changes
// Change cutting condition
ChangeCutTypeTo ("Large");
ChangeCutTypeTo ("Small");
ChangeCutTypeTo ("Medium");
ChangeCutTypeTo ("Mark");
ChangeCutTypeTo ("Vaporize");
ChangeCutTypeTo ("Dot mark");
// Change pierce condition
ChangePierceTypeTo ("Normal");
ChangePierceTypeTo ("Gentle");
ChangePierceTypeTo ("Mark");
ChangePierceTypeTo ("None");
Scrap Tooling Management
// Create or delete scrap tooling
EditScrapTooling (true); // Create
EditScrapTooling (false); // Delete
Laser CAM Settings
// Open settings panel
var settings = OpenLaserCAMSettings ();
// Interact with settings
settings.FindFirstChild ("OpenPlineProcess").AsComboBox ().Select ("Mark");
settings.FindFirstChild (c => c.ByName ("Cool at corners...")).Click ();
settings.FindAllChildren (c => c.ByClassName ("TextBox"))[1].AsTextBox ().Text = "5";
settings.FindFirstChild (c => c.ByName ("Mark forming footprint")).Click ();
Validation Helpers
Cut Condition Validation
// Check cutting condition matches expected value
CheckCutCondition ("Large");
CheckCutCondition ("Mark");
CheckCutCondition ("", 1); // With polyline index
// Internal: Uses Flux scripting
// var lpc = (Flux.LaserPathCut)((Flux.LaserStep)part.CutTech.AllSteps.ElementAtOrDefault(0));
// var result = lpc.CC.Name.ToString();
Pierce Condition Validation
// Check pierce condition
CheckPierceCondition ("Normal");
CheckPierceCondition ("Mark"); // Converted to "MarkPt" internally
CheckPierceCondition ("None"); // Converted to "" internally
CheckPierceCondition ("Gentle", 1); // With polyline index
Profile Validation
// Check laser cut profile against reference
CheckLaserCutProfile ("C150616", "test_normalProfile");
CheckLaserCutProfile ("C150616", "test_reversedProfile");
// Generates tooling pline data and compares with reference file
// Reference path: {Utils.tData}Test_{folder}/{filename}.txt
NC Code Validation
// Generate NC code and validate
CheckNC ("C122167", "addedmicrojointnc");
CheckNC ("C122167", "removedmicrojointnc");
// Reference path: {Utils.tData}Test_{folder}/{filename}.txt
Machine Configuration
// Configure test machine
Utils.ConfigureMachine (testMachineID); // Before tests
Utils.ConfigureMachine ("130167");
// Uninstall machine after tests
Utils.UninstallMachine (testMachineID);
// Temporary machine context
using var _ = new Utils.TmpMachine ("120057"); // Auto-uninstall when disposed
Reset Operations
// Reset Flux data to initial state
Utils.ResetFluxData ();
// Reset LTT settings
LTT.GeneralSettings.ResetLTTSettings ();
Script Execution
// Run Flux C# script
Utils.RunScript ("Flux.PartEditor.Current.Skin = CutCAM");
// Run script and capture output
var result = Utils.RunScriptWithOutput ("var result = Flux.Part.Current.Name;");
// Multi-line script
var result = Utils.RunScriptWithOutput (new List<string> {
"var part = Flux.Part.Current;",
"var lpc = (Flux.LaserPathCut)((Flux.LaserStep)part.CutTech.AllSteps.ElementAtOrDefault(0));",
"var result = lpc.CC.Name.ToString();"
});
// Dump console history
Utils.RunScriptWithOutput ("Flux.MConsole.DumpHistory (@\"" + Utils.tempPath + "temp.txt\");");
NC File Operations
// Generate NC code file
Utils.NCFileCreation (); // Creates temp.txt with NC code
// Render scene to file
Utils.RenderSceneToFile (Utils.tempPath + "test.png");
Part Operations
// Open specific part view
Utils.IsPartView (Utils.EPartView.Layout);
// Close current part
Utils.ClosePart (true); // With save
Utils.ClosePart (false); // Without save
// Select bendline
Utils.SelectBendline (3); // Bendline index
Nesting/Recompute Operations
// Recompute tooling
Nesting.Recompute ();
// Quick nest
Nesting.DoNewQuickNest ();
Common Test Workflows
Basic Test Flow
[Test (1519, "Test Description")]
public void TestMethod () {
// 1. Open file
Utils.OpenFile (Utils.tData + fxFile);
Thread.Sleep (500);
// 2. Navigate to feature (e.g., laser tooling)
Utils.Type ('l');
// 3. Perform action
LaserCutGlob (fxFile).FindFirstDescendant (a => a.ByName ("Reverse")).Click ();
// 4. Validate result
CheckLaserCutProfile ("C150616", "test_reversedProfile");
// 5. Clean up (auto-handled by framework)
}
Loop-Based Test Pattern
[Test (1520, "Changing the cutting condition")]
public void C122143 () {
Utils.OpenFile (Utils.tData + fxFile);
foreach (var cuttingType in new[] { "Small", "Medium", "Large" }) {
// Perform action
ChangeCutTypeTo (cuttingType);
// Validate each iteration
CheckCutCondition (cuttingType);
// Optional: Re-open for next iteration
Utils.OpenFile (Utils.tData + fxFile);
}
}
Settings Modification Pattern
[Test (ID, "Settings Test")]
public void TestSettings () {
Utils.OpenFile (Utils.tData + filename);
Utils.Type ('l');
var settings = OpenLaserCAMSettings ();
// Modify multiple settings
settings.FindFirstChild ("FieldName").AsTextBox ().Text = "25";
settings.FindFirstChild (c => c.ByName ("Checkbox Name")).Click ();
settings.FindFirstChild ("ComboField").AsComboBox ().Select ("Option");
Utils.Type (ESC); // Close settings
// Validate changes
CheckLaserCutProfile ("C200390", "test_Before0.5Approach");
}
File Comparison Pattern
[Test (ID, "NC Code Validation")]
public void TestNCCode () {
Utils.OpenFile (Utils.tData + fxFile);
Utils.Type ('l');
// Perform tooling operations
LaserCutGlob (fxFile).FindFirstDescendant (a => a.ByName ("Add")).Click ();
// Generate and validate NC file
CheckNC ("C122167", "addedmicrojointnc");
// Or validate using reference file
Utils.NCFileCreation ();
Assert.AreTextFilesEqual (
$"{Utils.tData}Test_C122167/addedmicrojointnc.txt",
Utils.tempPath + "temp.txt"
);
}
Multi-Step Validation Pattern
[Test (2539, "Complex Validation")]
public void Test_C145702 () {
Utils.OpenFile (Utils.tData + "countersink.geo");
var circlePt = Utils.MeasurePtToPixel (new (31.102, 7.319, 0));
Utils.MouseClick (circlePt);
// Assertion 1: Check initial state
Assert.True (Utils.MainWin.FindFirstChild ("Glob").FindFirstChild (c => c.ByName ("Layer")) is null);
// Perform action
Utils.Type ('l');
OpenLaserCAMSettings ().FindFirstChild (c => c.ByName ("Mark forming footprint")).Click ();
// Continue workflow
Utils.Type (ESC); Utils.Type ('r'); Utils.Type ('a');
Utils.MouseClick (circlePt);
// Assertion 2: Check action result
CheckCutCondition ("Mark");
// Assertion 3: Verify final state
Utils.Type ('2');
Utils.MouseClick (Utils.MeasurePtToPixel (new (31.091, 7.323, 0)));
Assert.AreEqual (
Utils.WaitForGlob ().FindFirstChild ("Layer").AsComboBox ().SelectedItem.Name,
"Footprint"
);
}
Helper Methods Reference
UI Element Helpers
// Main window reference
var mainWin = Utils.MainWin;
// Check if Flux is running
bool isRunning = Utils.IsRunning ();
// Get DPI
int dpi = Utils.DPI;
// Measure point to pixel conversion
var pixelPoint = Utils.MeasurePtToPixel (new (X, Y, Z));
File & Path Helpers
// Check if file is open
Utils.IsThisFileOpen ("123.fx");
// Dump automation tree
Utils.DumpAutomationElement (element, pathToFile);
Timing & Wait Operations
// Sleep with duration
Thread.Sleep (500); // 500ms
Thread.Sleep (1000); // 1 second
Thread.Sleep (1500); // 1.5 seconds
// Wait for conditions
Utils.WaitForFileExists ();
Utils.WaitForGlob ();
Utils.FindElement (() => ...); // With retry logic
Geometry Helpers
// Create measurement point (3D)
var point = new Utils.Measure (X, Y, Z);
var contourPt = new (153.946, 18.168);
// Measurement shortcuts
new (153.946, 91.549, 0)
new (50.15, 46.54)
new (31.102, 7.319, 0)
Quick Reference: Common Commands by Use Case
Creating a Basic Test
[Test (ID, "Description")]
public void Test_CaseID () {
Utils.OpenFile (Utils.tData + filename);
Utils.Type ('l');
// Perform actions
CheckLaserCutProfile ("CaseID", "test_name");
}
Testing UI Change
var element = Utils.MainWin.FindFirstDescendant (a => a.ByName ("Name"));
element.AsTextBox ().Text = "value";
Assert.AreEqual (element.AsTextBox ().Text, "value");
Testing Settings
var settings = OpenLaserCAMSettings ();
settings.FindFirstChild ("FieldName").AsTextBox ().Text = "25";
Utils.Type (ESC);
CheckNC ("CaseID", "test_name");
Testing Dropdown Selection
var combo = element.AsComboBox ();
combo.Select ("Option");
combo.Collapse ();
Assert.True (combo.Items.Any (e => e.Text = "Option"));
Loop Testing Multiple Values
foreach (var value in new[] { "Val1", "Val2", "Val3" }) {
Utils.OpenFile (Utils.tData + file);
ChangeValue (value);
ValidateValue (value);
}
Best Practices
✅ DO: - Use descriptive test names with test case IDs - Always clean
up resources in [FixtureCleanUp] - Use meaningful constants
for file paths and IDs - Add comments for non-obvious UI automation
steps - Use assertions with descriptive messages - Follow the test →
action → validate pattern
❌ DON’T: - Use magic numbers without constants - Leave resources uncleaned - Skip assertions in loops - Use generic variable names (g, h, s, etc. without context) - Hardcode long delays without reason - Mix test logic with assertions in complex expressions
This recipe book covers all major patterns and commands used in the Fluxtester framework for creating automated UI tests for the Flux application.