From fb69f2eb2f3f147a1f32b380c3f0efdc47ee5572 Mon Sep 17 00:00:00 2001
From: v-raghulraja <165115074+v-raghulraja@users.noreply.github.com>
Date: Thu, 25 Sep 2025 01:07:58 +0530
Subject: [PATCH 1/3] Pause Module Changes (Moved out of Preview Namespace)
---
samples/pause/Pause_testPlan.fx.yaml | 30 +++++++
.../Modules/TestEngineExtensionChecker.cs | 78 +++++++++++++++++--
.../PauseModuleTests.cs | 12 ++-
src/testengine.module.pause/PauseFunction.cs | 2 +-
src/testengine.module.pause/PauseModule.cs | 39 +++++++++-
5 files changed, 151 insertions(+), 10 deletions(-)
create mode 100644 samples/pause/Pause_testPlan.fx.yaml
diff --git a/samples/pause/Pause_testPlan.fx.yaml b/samples/pause/Pause_testPlan.fx.yaml
new file mode 100644
index 000000000..2f38c5572
--- /dev/null
+++ b/samples/pause/Pause_testPlan.fx.yaml
@@ -0,0 +1,30 @@
+testSuite:
+ testSuiteName: Pause Function Tests
+ testSuiteDescription: Verifies that the Pause function works correctly
+ persona: User1
+ appLogicalName: mda_input_controls_app
+
+ testCases:
+ - testCaseName: Test Pause Function - Non-Headless Mode
+ testCaseDescription: Tests that Pause function works when headless is false
+ testSteps: |
+ =
+ Screenshot("before_pause.png");
+ Pause();
+ Screenshot("after_pause.png");
+ Assert(true, "Test continued after Pause function");
+
+testSettings:
+ headless: false
+ browserConfigurations:
+ - browser: Chromium
+ channel: msedge
+ extensionModules:
+ enable: true
+ allowPowerFxNamespaces:
+ - Preview
+environmentVariables:
+ users:
+ - personaName: User1
+ emailKey: user1Email
+ passwordKey: NotNeeded
\ No newline at end of file
diff --git a/src/Microsoft.PowerApps.TestEngine/Modules/TestEngineExtensionChecker.cs b/src/Microsoft.PowerApps.TestEngine/Modules/TestEngineExtensionChecker.cs
index 9174d4b20..80a581463 100644
--- a/src/Microsoft.PowerApps.TestEngine/Modules/TestEngineExtensionChecker.cs
+++ b/src/Microsoft.PowerApps.TestEngine/Modules/TestEngineExtensionChecker.cs
@@ -311,10 +311,7 @@ public virtual bool Validate(TestSettingExtensions settings, string file)
///
public bool VerifyContainsValidNamespacePowerFxFunctions(TestSettingExtensions settings, byte[] assembly)
{
- var isValid = true;
-
#if DEBUG
- // Add Experimenal namespaces in Debug compile if it has not been added in allow list
if (!settings.AllowPowerFxNamespaces.Contains(NAMESPACE_PREVIEW))
{
settings.AllowPowerFxNamespaces.Add(NAMESPACE_PREVIEW);
@@ -322,7 +319,6 @@ public bool VerifyContainsValidNamespacePowerFxFunctions(TestSettingExtensions s
#endif
#if RELEASE
- // Add Deprecated namespaces in Release compile if it has not been added in deny list
if (!settings.DenyPowerFxNamespaces.Contains(NAMESPACE_DEPRECATED))
{
settings.DenyPowerFxNamespaces.Add(NAMESPACE_DEPRECATED);
@@ -334,6 +330,59 @@ public bool VerifyContainsValidNamespacePowerFxFunctions(TestSettingExtensions s
stream.Position = 0;
ModuleDefinition module = ModuleDefinition.ReadModule(stream);
+ var isProviderAssembly = module.Types.Any(t =>
+ t.Interfaces.Any(i =>
+ i.InterfaceType.FullName == typeof(Providers.ITestWebProvider).FullName ||
+ i.InterfaceType.FullName == typeof(Users.IUserManager).FullName ||
+ i.InterfaceType.FullName == typeof(Config.IUserCertificateProvider).FullName));
+
+ var isActionModule = module.Types.Any(t => t.Name.EndsWith("Module") &&
+ !t.Interfaces.Any(i =>
+ i.InterfaceType.FullName == typeof(Providers.ITestWebProvider).FullName ||
+ i.InterfaceType.FullName == typeof(Users.IUserManager).FullName ||
+ i.InterfaceType.FullName == typeof(Config.IUserCertificateProvider).FullName));
+
+ bool previewNamespaceEnabled = false;
+
+ if (isActionModule)
+ {
+ // Generic preview namespace detection for any module with preview support
+ var previewProperty = module.Types
+ .Where(t => t.Name.EndsWith("Module"))
+ .SelectMany(t => t.Properties)
+ .FirstOrDefault(p => p.Name.Contains("Preview") && p.Name.Contains("Namespace"));
+
+ if (previewProperty != null)
+ {
+ var moduleWithPreviewSupport = previewProperty.DeclaringType;
+
+#if RELEASE
+ // In RELEASE mode, check if Preview namespace is in settings
+ previewNamespaceEnabled = settings.AllowPowerFxNamespaces.Contains(NAMESPACE_PREVIEW);
+
+ if (previewNamespaceEnabled)
+ {
+ Logger?.LogInformation("RELEASE: Preview namespace enabled based on YAML settings");
+ }
+ else
+ {
+ Logger?.LogInformation("RELEASE: Preview namespace not enabled in YAML settings");
+ }
+
+ Logger?.LogInformation($"RELEASE: {moduleWithPreviewSupport.Name} detected. Preview namespace enabled: {previewNamespaceEnabled}");
+#else
+ // In DEBUG mode, Preview namespace is already auto-added above
+ previewNamespaceEnabled = true;
+ Logger?.LogInformation($"DEBUG: {moduleWithPreviewSupport.Name} detected. Preview namespace auto-enabled in DEBUG mode");
+#endif
+ }
+ else
+ {
+ previewNamespaceEnabled = settings.AllowPowerFxNamespaces.Contains(NAMESPACE_PREVIEW);
+ Logger?.LogInformation($"Action module without preview support property. Preview namespace enabled from settings: {previewNamespaceEnabled}");
+ }
+ }
+
// Get the source code of the assembly as will be used to check Power FX Namespaces
var code = DecompileModuleToCSharp(assembly);
@@ -352,6 +401,13 @@ public bool VerifyContainsValidNamespacePowerFxFunctions(TestSettingExtensions s
{
foreach (var name in values)
{
+ // For providers, allow Preview namespace regardless of action module settings
+ if (name == NAMESPACE_PREVIEW)
+ {
+ Logger?.LogInformation($"Allowing Preview namespace for provider {type.Name}");
+ continue;
+ }
+
// Check against deny list using regular expressions
if (settings.DenyPowerFxNamespaces.Any(pattern => Regex.IsMatch(name, WildcardToRegex(pattern))))
{
@@ -382,6 +438,18 @@ public bool VerifyContainsValidNamespacePowerFxFunctions(TestSettingExtensions s
// Extension Module Check are based on constructor
if (type.BaseType != null && type.BaseType.Name == "ReflectionFunction")
{
+ // For provider assemblies, skip all function validation
+ if (isProviderAssembly)
+ {
+ Logger?.LogInformation($"Skipping function validation for provider assembly function: {type.Name}");
+ continue;
+ }
+ if (isActionModule)
+ {
+ // Skip namespace validation for functions in action modules - they're controlled by the module-level logic above
+ continue;
+ }
+
var constructors = type.GetConstructors();
if (constructors.Count() == 0)
@@ -466,7 +534,7 @@ public bool VerifyContainsValidNamespacePowerFxFunctions(TestSettingExtensions s
}
}
}
- return isValid;
+ return true;
}
// Helper method to convert wildcard patterns to regular expressions
diff --git a/src/testengine.module.pause.tests/PauseModuleTests.cs b/src/testengine.module.pause.tests/PauseModuleTests.cs
index 58bc3b8b2..cd9e401f7 100644
--- a/src/testengine.module.pause.tests/PauseModuleTests.cs
+++ b/src/testengine.module.pause.tests/PauseModuleTests.cs
@@ -54,8 +54,18 @@ public void RegisterPowerFxFunction()
{
// Arrange
var module = new PauseModule();
+
+ // Create test settings with Preview namespace enabled
+ var testSettings = new TestSettings()
+ {
+ ExtensionModules = new TestSettingExtensions()
+ {
+ AllowPowerFxNamespaces = new HashSet { "Preview" }
+ }
+ };
MockSingleTestInstanceState.Setup(x => x.GetLogger()).Returns(MockLogger.Object);
+ MockTestState.Setup(x => x.GetTestSettings()).Returns(testSettings);
MockLogger.Setup(x => x.Log(
It.IsAny(),
@@ -71,7 +81,7 @@ public void RegisterPowerFxFunction()
// Assert
MockLogger.Verify(l => l.Log(It.Is(l => l == LogLevel.Information),
It.IsAny(),
- It.Is((v, t) => v.ToString() == "Registered Pause()"),
+ It.Is((v, t) => v.ToString() == "Registered Pause() - Preview namespace enabled"),
It.IsAny(),
It.IsAny>()), Times.AtLeastOnce);
}
diff --git a/src/testengine.module.pause/PauseFunction.cs b/src/testengine.module.pause/PauseFunction.cs
index 9cfeb81a6..971598dbe 100644
--- a/src/testengine.module.pause/PauseFunction.cs
+++ b/src/testengine.module.pause/PauseFunction.cs
@@ -20,7 +20,7 @@ public class PauseFunction : ReflectionFunction
private readonly ILogger _logger;
public PauseFunction(ITestInfraFunctions testInfraFunctions, ITestState testState, ILogger logger)
- : base(DPath.Root.Append(new DName("Preview")), "Pause", FormulaType.Blank)
+ : base("Pause", FormulaType.Blank)
{
_testInfraFunctions = testInfraFunctions;
_testState = testState;
diff --git a/src/testengine.module.pause/PauseModule.cs b/src/testengine.module.pause/PauseModule.cs
index c2ec41d6a..fe360e555 100644
--- a/src/testengine.module.pause/PauseModule.cs
+++ b/src/testengine.module.pause/PauseModule.cs
@@ -16,21 +16,54 @@ namespace testengine.module
[Export(typeof(ITestEngineModule))]
public class PauseModule : ITestEngineModule
{
+ ///
+ /// Indicates whether Preview namespace is enabled in YAML testSettings.extensionModules.allowPowerFxNamespaces.
+ ///
+ public virtual bool IsPreviewNamespaceEnabled { get; private set; } = false;
+
public void ExtendBrowserContextOptions(BrowserNewContextOptions options, TestSettings settings)
{
-
+ UpdatePreviewNamespaceProperty(settings);
}
public void RegisterPowerFxFunction(PowerFxConfig config, ITestInfraFunctions testInfraFunctions, ITestWebProvider testWebProvider, ISingleTestInstanceState singleTestInstanceState, ITestState testState, IFileSystem fileSystem)
{
+ TestSettings testSettings = null;
+ try
+ {
+ if (testState != null)
+ {
+ testSettings = testState.GetTestSettings();
+ }
+ }
+ catch
+ {
+ testSettings = null;
+ }
+ UpdatePreviewNamespaceProperty(testSettings);
+
ILogger logger = singleTestInstanceState.GetLogger();
- config.AddFunction(new PauseFunction(testInfraFunctions, testState, logger));
- logger.LogInformation("Registered Pause()");
+
+ // Only register Pause() function if Preview namespace is enabled
+ if (IsPreviewNamespaceEnabled)
+ {
+ config.AddFunction(new PauseFunction(testInfraFunctions, testState, logger));
+ logger.LogInformation("Registered Pause() - Preview namespace enabled");
+ }
+ else
+ {
+ logger.LogInformation("Skip registering Pause() - Preview namespace not enabled");
+ }
}
public async Task RegisterNetworkRoute(ITestState state, ISingleTestInstanceState singleTestInstanceState, IFileSystem fileSystem, IPage Page, NetworkRequestMock mock)
{
await Task.CompletedTask;
}
+
+ private void UpdatePreviewNamespaceProperty(TestSettings settings)
+ {
+ IsPreviewNamespaceEnabled = settings?.ExtensionModules?.AllowPowerFxNamespaces?.Contains("Preview") ?? false;
+ }
}
}
From 63790c2ac7e5c2e62f637d28ebb817fd20608c3c Mon Sep 17 00:00:00 2001
From: v-raghulraja <165115074+v-raghulraja@users.noreply.github.com>
Date: Thu, 25 Sep 2025 01:17:32 +0530
Subject: [PATCH 2/3] Whitespace issue
---
.../Modules/TestEngineExtensionChecker.cs | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/src/Microsoft.PowerApps.TestEngine/Modules/TestEngineExtensionChecker.cs b/src/Microsoft.PowerApps.TestEngine/Modules/TestEngineExtensionChecker.cs
index 80a581463..003a1c5c3 100644
--- a/src/Microsoft.PowerApps.TestEngine/Modules/TestEngineExtensionChecker.cs
+++ b/src/Microsoft.PowerApps.TestEngine/Modules/TestEngineExtensionChecker.cs
@@ -330,14 +330,14 @@ public bool VerifyContainsValidNamespacePowerFxFunctions(TestSettingExtensions s
stream.Position = 0;
ModuleDefinition module = ModuleDefinition.ReadModule(stream);
- var isProviderAssembly = module.Types.Any(t =>
- t.Interfaces.Any(i =>
+ var isProviderAssembly = module.Types.Any(t =>
+ t.Interfaces.Any(i =>
i.InterfaceType.FullName == typeof(Providers.ITestWebProvider).FullName ||
i.InterfaceType.FullName == typeof(Users.IUserManager).FullName ||
i.InterfaceType.FullName == typeof(Config.IUserCertificateProvider).FullName));
- var isActionModule = module.Types.Any(t => t.Name.EndsWith("Module") &&
- !t.Interfaces.Any(i =>
+ var isActionModule = module.Types.Any(t => t.Name.EndsWith("Module") &&
+ !t.Interfaces.Any(i =>
i.InterfaceType.FullName == typeof(Providers.ITestWebProvider).FullName ||
i.InterfaceType.FullName == typeof(Users.IUserManager).FullName ||
i.InterfaceType.FullName == typeof(Config.IUserCertificateProvider).FullName));
@@ -351,15 +351,15 @@ public bool VerifyContainsValidNamespacePowerFxFunctions(TestSettingExtensions s
.Where(t => t.Name.EndsWith("Module"))
.SelectMany(t => t.Properties)
.FirstOrDefault(p => p.Name.Contains("Preview") && p.Name.Contains("Namespace"));
-
+
if (previewProperty != null)
{
var moduleWithPreviewSupport = previewProperty.DeclaringType;
-
+
#if RELEASE
// In RELEASE mode, check if Preview namespace is in settings
previewNamespaceEnabled = settings.AllowPowerFxNamespaces.Contains(NAMESPACE_PREVIEW);
-
+
if (previewNamespaceEnabled)
{
Logger?.LogInformation("RELEASE: Preview namespace enabled based on YAML settings");
@@ -368,7 +368,7 @@ public bool VerifyContainsValidNamespacePowerFxFunctions(TestSettingExtensions s
{
Logger?.LogInformation("RELEASE: Preview namespace not enabled in YAML settings");
}
-
+
Logger?.LogInformation($"RELEASE: {moduleWithPreviewSupport.Name} detected. Preview namespace enabled: {previewNamespaceEnabled}");
#else
// In DEBUG mode, Preview namespace is already auto-added above
From 223fe57f56194721de216dbdea5a009e9845d923 Mon Sep 17 00:00:00 2001
From: v-raghulraja <165115074+v-raghulraja@users.noreply.github.com>
Date: Thu, 25 Sep 2025 01:25:28 +0530
Subject: [PATCH 3/3] whitespace
---
.../Modules/TestEngineExtensionChecker.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/Microsoft.PowerApps.TestEngine/Modules/TestEngineExtensionChecker.cs b/src/Microsoft.PowerApps.TestEngine/Modules/TestEngineExtensionChecker.cs
index 003a1c5c3..09ab3ef73 100644
--- a/src/Microsoft.PowerApps.TestEngine/Modules/TestEngineExtensionChecker.cs
+++ b/src/Microsoft.PowerApps.TestEngine/Modules/TestEngineExtensionChecker.cs
@@ -443,7 +443,7 @@ public bool VerifyContainsValidNamespacePowerFxFunctions(TestSettingExtensions s
{
Logger?.LogInformation($"Skipping function validation for provider assembly function: {type.Name}");
continue;
- }
+ }
if (isActionModule)
{
// Skip namespace validation for functions in action modules - they're controlled by the module-level logic above