diff --git a/Elsa.Extensions.sln b/Elsa.Extensions.sln
index 7a22cadf..80bfebc4 100644
--- a/Elsa.Extensions.sln
+++ b/Elsa.Extensions.sln
@@ -297,6 +297,14 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Scheduling.Quartz.Unit
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Scheduling.Quartz.ComponentTests", "test\modules\scheduling\Elsa.Scheduling.Quartz.ComponentTests\Elsa.Scheduling.Quartz.ComponentTests.csproj", "{50798373-8A89-4159-BFD9-830D259538D6}"
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "fakedata", "fakedata", "{3A829F79-B19C-4100-929E-E78B86001D00}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.FakeData", "src\modules\fakedata\Elsa.FakeData\Elsa.FakeData.csproj", "{5501314E-52CF-4D02-86C0-180C4F4470F2}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "fakedata", "fakedata", "{DCDBD383-FB19-4174-B51D-968613BEEB35}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.FakeData.UnitTests", "test\modules\fakedata\Elsa.FakeData.UnitTests\Elsa.FakeData.UnitTests.csproj", "{2F9BD705-112C-44FB-81BD-48515C308CEF}"
+EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "agents", "agents", "{0125BAC5-45B7-4E9B-8A2B-55F075BF537A}"
ProjectSection(SolutionItems) = preProject
.github\agents\release-notes.agent.md = .github\agents\release-notes.agent.md
@@ -1456,6 +1464,30 @@ Global
{50798373-8A89-4159-BFD9-830D259538D6}.Release|x64.Build.0 = Release|Any CPU
{50798373-8A89-4159-BFD9-830D259538D6}.Release|x86.ActiveCfg = Release|Any CPU
{50798373-8A89-4159-BFD9-830D259538D6}.Release|x86.Build.0 = Release|Any CPU
+ {5501314E-52CF-4D02-86C0-180C4F4470F2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {5501314E-52CF-4D02-86C0-180C4F4470F2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {5501314E-52CF-4D02-86C0-180C4F4470F2}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {5501314E-52CF-4D02-86C0-180C4F4470F2}.Debug|x64.Build.0 = Debug|Any CPU
+ {5501314E-52CF-4D02-86C0-180C4F4470F2}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {5501314E-52CF-4D02-86C0-180C4F4470F2}.Debug|x86.Build.0 = Debug|Any CPU
+ {5501314E-52CF-4D02-86C0-180C4F4470F2}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {5501314E-52CF-4D02-86C0-180C4F4470F2}.Release|Any CPU.Build.0 = Release|Any CPU
+ {5501314E-52CF-4D02-86C0-180C4F4470F2}.Release|x64.ActiveCfg = Release|Any CPU
+ {5501314E-52CF-4D02-86C0-180C4F4470F2}.Release|x64.Build.0 = Release|Any CPU
+ {5501314E-52CF-4D02-86C0-180C4F4470F2}.Release|x86.ActiveCfg = Release|Any CPU
+ {5501314E-52CF-4D02-86C0-180C4F4470F2}.Release|x86.Build.0 = Release|Any CPU
+ {2F9BD705-112C-44FB-81BD-48515C308CEF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {2F9BD705-112C-44FB-81BD-48515C308CEF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {2F9BD705-112C-44FB-81BD-48515C308CEF}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {2F9BD705-112C-44FB-81BD-48515C308CEF}.Debug|x64.Build.0 = Debug|Any CPU
+ {2F9BD705-112C-44FB-81BD-48515C308CEF}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {2F9BD705-112C-44FB-81BD-48515C308CEF}.Debug|x86.Build.0 = Debug|Any CPU
+ {2F9BD705-112C-44FB-81BD-48515C308CEF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {2F9BD705-112C-44FB-81BD-48515C308CEF}.Release|Any CPU.Build.0 = Release|Any CPU
+ {2F9BD705-112C-44FB-81BD-48515C308CEF}.Release|x64.ActiveCfg = Release|Any CPU
+ {2F9BD705-112C-44FB-81BD-48515C308CEF}.Release|x64.Build.0 = Release|Any CPU
+ {2F9BD705-112C-44FB-81BD-48515C308CEF}.Release|x86.ActiveCfg = Release|Any CPU
+ {2F9BD705-112C-44FB-81BD-48515C308CEF}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -1587,6 +1619,10 @@ Global
{65B9F528-568B-4E0E-894E-F22E0B7C64BB} = {6E46B8AD-FA47-474F-B959-0B530771C28C}
{50798373-8A89-4159-BFD9-830D259538D6} = {6E46B8AD-FA47-474F-B959-0B530771C28C}
{0125BAC5-45B7-4E9B-8A2B-55F075BF537A} = {D0212324-351E-4CA6-95EE-27754B5367CC}
+ {3A829F79-B19C-4100-929E-E78B86001D00} = {30CF0330-4B09-4784-B499-46BED303810B}
+ {5501314E-52CF-4D02-86C0-180C4F4470F2} = {3A829F79-B19C-4100-929E-E78B86001D00}
+ {DCDBD383-FB19-4174-B51D-968613BEEB35} = {3DDE6F89-531C-47F8-9CD7-7A4E6984FA48}
+ {2F9BD705-112C-44FB-81BD-48515C308CEF} = {DCDBD383-FB19-4174-B51D-968613BEEB35}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {11A771DA-B728-445E-8A88-AE1C84C3B3A6}
diff --git a/src/modules/fakedata/Elsa.FakeData/Activities/GenerateFakeDataActivity.cs b/src/modules/fakedata/Elsa.FakeData/Activities/GenerateFakeDataActivity.cs
new file mode 100644
index 00000000..c010578d
--- /dev/null
+++ b/src/modules/fakedata/Elsa.FakeData/Activities/GenerateFakeDataActivity.cs
@@ -0,0 +1,74 @@
+using Bogus;
+using Elsa.Extensions;
+using Elsa.Workflows;
+using Elsa.Workflows.Attributes;
+using Elsa.Workflows.Models;
+
+namespace Elsa.FakeData.Activities;
+
+///
+/// Provides a base implementation for activities that generate collections of fake data
+/// using the Bogus library.
+///
+public abstract class GenerateFakeDataActivity : CodeActivity where T : class
+{
+ ///
+ protected GenerateFakeDataActivity(string? source = null, int? line = null) : base(source, line)
+ {
+ }
+
+ ///
+ /// The number of fake records to generate.
+ ///
+ [Input(
+ DisplayName = "Number of records",
+ Description = "The number of fake records to generate. Default: 10")]
+ public Input Count { get; set; } = new(10);
+
+ ///
+ /// The locale to use when generating fake data (e.g. 'en', 'de', 'fr', 'nl').
+ /// See the Bogus locale list for all supported values.
+ ///
+ [Input(
+ DisplayName = "Locale",
+ Description = "The locale to use when generating fake data (e.g. 'en', 'de', 'fr', 'nl'). Default: en")]
+ public Input Locale { get; set; } = new("en");
+
+ ///
+ /// A seed value for the random number generator.
+ /// Providing a seed will ensure that the same fake data is generated on each run, which can be useful for deterministic testing.
+ /// If not provided, a random seed will be used, resulting in different data on each execution.
+ ///
+ [Input(
+ DisplayName = "Seed",
+ Description = "With a seed, each run will produce the identical data (for deterministic tests).")]
+ public Input Seed { get; set; } = new((int?)null);
+
+ ///
+ protected override ValueTask ExecuteAsync(ActivityExecutionContext context)
+ {
+ var count = Count.Get(context);
+
+ if (count < 0)
+ throw new ArgumentOutOfRangeException(nameof(Count), count, "The number of records to generate must be zero or greater.");
+
+ var locale = Locale.GetOrDefault(context) ?? "en";
+ var seed = Seed.GetOrDefault(context, () => null);
+
+ var faker = CreateFaker(locale, seed);
+ var items = faker.Generate(count);
+
+ context.Set(Result, items.ToArray());
+
+ return ValueTask.CompletedTask;
+ }
+ }
+
+ ///
+ /// Creates a configured instance for the given locale.
+ ///
+ /// The locale string (e.g. "en", "de", "fr").
+ /// An optional seed value for deterministic data generation.
+ /// A configured instance.
+ protected abstract Faker CreateFaker(string locale, int? seed);
+}
diff --git a/src/modules/fakedata/Elsa.FakeData/Activities/GenerateFakeOrders.cs b/src/modules/fakedata/Elsa.FakeData/Activities/GenerateFakeOrders.cs
new file mode 100644
index 00000000..3d4ac861
--- /dev/null
+++ b/src/modules/fakedata/Elsa.FakeData/Activities/GenerateFakeOrders.cs
@@ -0,0 +1,43 @@
+using System.Globalization;
+using System.Runtime.CompilerServices;
+using Bogus;
+using Elsa.FakeData.Extensions;
+using Elsa.FakeData.Models;
+using Elsa.Workflows;
+using Elsa.Workflows.Attributes;
+
+namespace Elsa.FakeData.Activities;
+
+///
+/// Generates a collection of fake records.
+///
+[Activity(
+ Namespace = "Elsa",
+ Category = "Fake Data",
+ DisplayName = "Generate Orders",
+ Description = "Generates a collection of fake order records.",
+ Kind = ActivityKind.Task)]
+public class GenerateFakeOrders : GenerateFakeDataActivity
+{
+ ///
+ public GenerateFakeOrders([CallerFilePath] string? source = null, [CallerLineNumber] int? line = null) : base(source, line)
+ {
+ }
+
+ ///
+ protected override Faker CreateFaker(string locale, int? seed)
+ {
+ return new Faker(locale)
+ .When(seed is not null, f => f.UseSeed(seed!.Value))
+ .RuleFor(o => o.Id, f => f.Random.Guid())
+ .RuleFor(o => o.OrderNumber, f => f.Random.Number(100_000, 1_000_000_000).ToString(CultureInfo.InvariantCulture))
+ .RuleFor(o => o.OrderDate, f => f.Date.Past())
+ .RuleFor(o => o.Status, f => f.PickRandom("Pending", "Processing", "Shipped", "Delivered", "Cancelled"))
+ .RuleFor(o => o.CustomerName, f => f.Person.FullName)
+ .RuleFor(o => o.CustomerEmail, f => f.Person.Email)
+ .RuleFor(o => o.ShippingAddress, f => f.Address.FullAddress())
+ .RuleFor(o => o.SubTotal, f => f.Finance.Amount(10, 500))
+ .RuleFor(o => o.Tax, (_, o) => Math.Round(o.SubTotal * 0.1m, 2))
+ .RuleFor(o => o.Total, (_, o) => o.SubTotal + o.Tax);
+ }
+}
diff --git a/src/modules/fakedata/Elsa.FakeData/Activities/GenerateFakePersons.cs b/src/modules/fakedata/Elsa.FakeData/Activities/GenerateFakePersons.cs
new file mode 100644
index 00000000..16bf67a2
--- /dev/null
+++ b/src/modules/fakedata/Elsa.FakeData/Activities/GenerateFakePersons.cs
@@ -0,0 +1,45 @@
+using System.Runtime.CompilerServices;
+using Bogus;
+using Elsa.FakeData.Extensions;
+using Elsa.FakeData.Models;
+using Elsa.Workflows;
+using Elsa.Workflows.Attributes;
+
+namespace Elsa.FakeData.Activities;
+
+///
+/// Generates a collection of fake records.
+///
+[Activity(
+ Namespace = "Elsa",
+ Category = "Fake Data",
+ DisplayName = "Generate Persons",
+ Description = "Generates a collection of fake person records.",
+ Kind = ActivityKind.Task)]
+public class GenerateFakePersons : GenerateFakeDataActivity
+{
+ ///
+ public GenerateFakePersons([CallerFilePath] string? source = null, [CallerLineNumber] int? line = null) : base(source, line)
+ {
+ }
+
+ ///
+ protected override Faker CreateFaker(string locale, int? seed)
+ {
+ return new Faker(locale)
+ .When(seed is not null, f => f.UseSeed(seed!.Value))
+ .RuleFor(p => p.Id, f => f.Random.Guid())
+ .RuleFor(p => p.FirstName, f => f.Person.FirstName)
+ .RuleFor(p => p.LastName, f => f.Person.LastName)
+ .RuleFor(p => p.FullName, (f) => f.Person.FullName)
+ .RuleFor(p => p.Email, (f, p) => f.Person.Email)
+ .RuleFor(p => p.Phone, f => f.Phone.PhoneNumber())
+ .RuleFor(p => p.DateOfBirth, f => f.Date.Past(80, new DateTime(2000, 1, 1)));
+ .RuleFor(p => p.Gender, f => f.PickRandom("Male", "Female", "Non-binary"))
+ .RuleFor(p => p.Address, f => f.Address.StreetAddress())
+ .RuleFor(p => p.City, f => f.Address.City())
+ .RuleFor(p => p.State, f => f.Address.State())
+ .RuleFor(p => p.ZipCode, f => f.Address.ZipCode())
+ .RuleFor(p => p.Country, f => f.Address.Country());
+ }
+}
diff --git a/src/modules/fakedata/Elsa.FakeData/Activities/GenerateFakeProducts.cs b/src/modules/fakedata/Elsa.FakeData/Activities/GenerateFakeProducts.cs
new file mode 100644
index 00000000..b69eddb2
--- /dev/null
+++ b/src/modules/fakedata/Elsa.FakeData/Activities/GenerateFakeProducts.cs
@@ -0,0 +1,40 @@
+using System.Runtime.CompilerServices;
+using Bogus;
+using Elsa.FakeData.Extensions;
+using Elsa.FakeData.Models;
+using Elsa.Workflows;
+using Elsa.Workflows.Attributes;
+
+namespace Elsa.FakeData.Activities;
+
+///
+/// Generates a collection of fake records.
+///
+[Activity(
+ Namespace = "Elsa",
+ Category = "Fake Data",
+ DisplayName = "Generate Products",
+ Description = "Generates a collection of fake product records.",
+ Kind = ActivityKind.Task)]
+public class GenerateFakeProducts : GenerateFakeDataActivity
+{
+ ///
+ public GenerateFakeProducts([CallerFilePath] string? source = null, [CallerLineNumber] int? line = null) : base(source, line)
+ {
+ }
+
+ ///
+ protected override Faker CreateFaker(string locale, int? seed)
+ {
+ return new Faker(locale)
+ .When(seed is not null, f => f.UseSeed(seed!.Value))
+ .RuleFor(p => p.Id, f => f.Random.Guid())
+ .RuleFor(p => p.Name, f => f.Commerce.ProductName())
+ .RuleFor(p => p.Description, f => f.Commerce.ProductDescription())
+ .RuleFor(p => p.Price, f => f.Finance.Amount(1, 1000))
+ .RuleFor(p => p.Category, f => f.Commerce.Categories(1)[0])
+ .RuleFor(p => p.Department, f => f.Commerce.Department())
+ .RuleFor(p => p.Rating, f => f.Random.Number(1, 5))
+ .RuleFor(p => p.Stock, f => f.Random.Int(0, 1000));
+ }
+}
diff --git a/src/modules/fakedata/Elsa.FakeData/Activities/GenerateFakeUsers.cs b/src/modules/fakedata/Elsa.FakeData/Activities/GenerateFakeUsers.cs
new file mode 100644
index 00000000..2e739534
--- /dev/null
+++ b/src/modules/fakedata/Elsa.FakeData/Activities/GenerateFakeUsers.cs
@@ -0,0 +1,40 @@
+using System.Runtime.CompilerServices;
+using Bogus;
+using Elsa.FakeData.Extensions;
+using Elsa.FakeData.Models;
+using Elsa.Workflows;
+using Elsa.Workflows.Attributes;
+
+namespace Elsa.FakeData.Activities;
+
+///
+/// Generates a collection of fake records.
+///
+[Activity(
+ Namespace = "Elsa",
+ Category = "Fake Data",
+ DisplayName = "Generate Users",
+ Description = "Generates a collection of fake user records.",
+ Kind = ActivityKind.Task)]
+public class GenerateFakeUsers : GenerateFakeDataActivity
+{
+ ///
+ public GenerateFakeUsers([CallerFilePath] string? source = null, [CallerLineNumber] int? line = null) : base(source, line)
+ {
+ }
+
+ ///
+ protected override Faker CreateFaker(string locale, int? seed)
+ {
+ return new Faker(locale)
+ .When(seed is not null, f => f.UseSeed(seed!.Value))
+ .RuleFor(u => u.Id, f => f.Random.Guid())
+ .RuleFor(u => u.FirstName, f => f.Person.FirstName)
+ .RuleFor(u => u.LastName, f => f.Person.LastName)
+ .RuleFor(u => u.Username, f => f.Person.UserName)
+ .RuleFor(u => u.Email, f => f.Person.Email)
+ .RuleFor(u => u.Avatar, f => f.Person.Avatar)
+ .RuleFor(u => u.Roles, f => [f.PickRandom("Admin", "User", "Moderator", "Guest")])
+ .RuleFor(u => u.CreatedAt, f => f.Date.Past(5));
+ }
+}
diff --git a/src/modules/fakedata/Elsa.FakeData/Elsa.FakeData.csproj b/src/modules/fakedata/Elsa.FakeData/Elsa.FakeData.csproj
new file mode 100644
index 00000000..6e3a6ad0
--- /dev/null
+++ b/src/modules/fakedata/Elsa.FakeData/Elsa.FakeData.csproj
@@ -0,0 +1,25 @@
+
+
+
+
+ Provides activities to generate fake data for testing and benchmarking purposes.
+
+ elsa module fakedata testing benchmarking bogus
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/modules/fakedata/Elsa.FakeData/Extensions/ModuleExtensions.cs b/src/modules/fakedata/Elsa.FakeData/Extensions/ModuleExtensions.cs
new file mode 100644
index 00000000..d577690b
--- /dev/null
+++ b/src/modules/fakedata/Elsa.FakeData/Extensions/ModuleExtensions.cs
@@ -0,0 +1,19 @@
+using Elsa.Extensions;
+using Elsa.FakeData.Features;
+using Elsa.Features.Services;
+
+namespace Elsa.FakeData.Extensions;
+
+///
+/// Provides extension methods for configuring fake data services.
+///
+public static class ModuleExtensions
+{
+ ///
+ /// Installs the FakeData module.
+ ///
+ public static IModule UseFakeData(this IModule module, Action? configure = null)
+ {
+ return module.Use(configure);
+ }
+}
\ No newline at end of file
diff --git a/src/modules/fakedata/Elsa.FakeData/Extensions/ObjectExtensions.cs b/src/modules/fakedata/Elsa.FakeData/Extensions/ObjectExtensions.cs
new file mode 100644
index 00000000..a96eb6e3
--- /dev/null
+++ b/src/modules/fakedata/Elsa.FakeData/Extensions/ObjectExtensions.cs
@@ -0,0 +1,9 @@
+namespace Elsa.FakeData.Extensions;
+
+internal static class ObjectExtensions
+{
+ public static T When(this T obj, bool condition, Func action)
+ {
+ return condition ? action(obj) : obj;
+ }
+}
diff --git a/src/modules/fakedata/Elsa.FakeData/Features/FakeDataFeature.cs b/src/modules/fakedata/Elsa.FakeData/Features/FakeDataFeature.cs
new file mode 100644
index 00000000..5e863d43
--- /dev/null
+++ b/src/modules/fakedata/Elsa.FakeData/Features/FakeDataFeature.cs
@@ -0,0 +1,22 @@
+using Elsa.Extensions;
+using Elsa.Features.Abstractions;
+using Elsa.Features.Services;
+
+namespace Elsa.FakeData.Features;
+
+///
+/// A feature that provides activities to generate fake data for testing and benchmarking purposes.
+///
+public class FakeDataFeature : FeatureBase
+{
+ ///
+ public FakeDataFeature(IModule module) : base(module)
+ {
+ }
+
+ ///
+ public override void Configure()
+ {
+ Module.AddActivitiesFrom();
+ }
+}
\ No newline at end of file
diff --git a/src/modules/fakedata/Elsa.FakeData/FodyWeavers.xml b/src/modules/fakedata/Elsa.FakeData/FodyWeavers.xml
new file mode 100644
index 00000000..5e025acb
--- /dev/null
+++ b/src/modules/fakedata/Elsa.FakeData/FodyWeavers.xml
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/modules/fakedata/Elsa.FakeData/Models/FakeOrder.cs b/src/modules/fakedata/Elsa.FakeData/Models/FakeOrder.cs
new file mode 100644
index 00000000..9aaa208c
--- /dev/null
+++ b/src/modules/fakedata/Elsa.FakeData/Models/FakeOrder.cs
@@ -0,0 +1,18 @@
+namespace Elsa.FakeData.Models;
+
+///
+/// Represents a fake order record.
+///
+public class FakeOrder
+{
+ public required Guid Id { get; set; }
+ public required string OrderNumber { get; set; }
+ public required DateTime OrderDate { get; set; }
+ public required string Status { get; set; }
+ public required string CustomerName { get; set; }
+ public required string CustomerEmail { get; set; }
+ public required string ShippingAddress { get; set; }
+ public required decimal SubTotal { get; set; }
+ public required decimal Tax { get; set; }
+ public required decimal Total { get; set; }
+}
\ No newline at end of file
diff --git a/src/modules/fakedata/Elsa.FakeData/Models/FakePerson.cs b/src/modules/fakedata/Elsa.FakeData/Models/FakePerson.cs
new file mode 100644
index 00000000..0c186938
--- /dev/null
+++ b/src/modules/fakedata/Elsa.FakeData/Models/FakePerson.cs
@@ -0,0 +1,21 @@
+namespace Elsa.FakeData.Models;
+
+///
+/// Represents a fake person record.
+///
+public class FakePerson
+{
+ public required Guid Id { get; set; }
+ public required string FirstName { get; set; }
+ public required string LastName { get; set; }
+ public required string FullName { get; set; }
+ public required string Email { get; set; }
+ public required string Phone { get; set; }
+ public required DateTime DateOfBirth { get; set; }
+ public required string Gender { get; set; }
+ public required string Address { get; set; }
+ public required string City { get; set; }
+ public required string State { get; set; }
+ public required string ZipCode { get; set; }
+ public required string Country { get; set; }
+}
diff --git a/src/modules/fakedata/Elsa.FakeData/Models/FakeProduct.cs b/src/modules/fakedata/Elsa.FakeData/Models/FakeProduct.cs
new file mode 100644
index 00000000..ee506a95
--- /dev/null
+++ b/src/modules/fakedata/Elsa.FakeData/Models/FakeProduct.cs
@@ -0,0 +1,16 @@
+namespace Elsa.FakeData.Models;
+
+///
+/// Represents a fake product record.
+///
+public class FakeProduct
+{
+ public required Guid Id { get; set; }
+ public required string Name { get; set; }
+ public required string Description { get; set; }
+ public required decimal Price { get; set; }
+ public required string Category { get; set; }
+ public required string Department { get; set; }
+ public required int Rating { get; set; }
+ public required int Stock { get; set; }
+}
diff --git a/src/modules/fakedata/Elsa.FakeData/Models/FakeUser.cs b/src/modules/fakedata/Elsa.FakeData/Models/FakeUser.cs
new file mode 100644
index 00000000..21517926
--- /dev/null
+++ b/src/modules/fakedata/Elsa.FakeData/Models/FakeUser.cs
@@ -0,0 +1,16 @@
+namespace Elsa.FakeData.Models;
+
+///
+/// Represents a fake user account record.
+///
+public class FakeUser
+{
+ public required Guid Id { get; set; }
+ public required string Username { get; set; }
+ public required string Email { get; set; }
+ public required string FirstName { get; set; }
+ public required string LastName { get; set; }
+ public required string Avatar { get; set; }
+ public required string[] Roles { get; set; }
+ public required DateTime CreatedAt { get; set; }
+}
diff --git a/src/modules/fakedata/Elsa.FakeData/README.md b/src/modules/fakedata/Elsa.FakeData/README.md
new file mode 100644
index 00000000..929b42fc
--- /dev/null
+++ b/src/modules/fakedata/Elsa.FakeData/README.md
@@ -0,0 +1,163 @@
+# Fake Data Extension
+
+
+ 📖 Table of Contents
+
+ - Overview
+ - Features
+ -
+ Getting Started
+
+
+ -
+ Configuration
+
+
+ - Usage
+ - Activities
+ - Examples
+ - Planned Features
+ - Limitations
+ - Troubleshooting
+ - Notes & Comments
+
+
+
+## 🧠 Overview
+
+This package extends [Elsa Workflows](https://github.com/elsa-workflows/elsa-core) with support for **fake data**.
+It introduces custom activities that make it easy to generate some fake data for testing, prototyping, or any other purpose where you might need to generate random data within your workflows.
+
+## ✨ Key Features
+
+- Activities: `GenerateFakeOrders`, `GenerateFakePersons`, `GenerateFakeProducts` and `GenerateFakeUsers`
+- Configurable output: specify the number of items to generate
+- Deterministic if needed: option to set a seed for reproducible results
+
+---
+
+## ⚡ Getting Started
+
+### 📋 Prerequisites
+
+- Elsa Workflows **3.6** or higher installed in your project.
+
+## 🛠 Installation
+
+The following NuGet packages are available for this extension:
+
+```bash
+Elsa.FakeData
+```
+
+You can install the clients via NuGet:
+
+```bash
+dotnet add package Elsa.FakeData
+```
+
+## ⚙️ Configuration
+
+### Program.cs
+
+Register the extension in your application startup:
+
+```csharp
+using Elsa.Extensions;
+using Elsa.FakeData.Extensions;
+
+services.AddElsa(elsa =>
+{
+ elsa.UseFakeData();
+}
+```
+
+---
+
+## 📌 Usage
+
+Once the extension is registered with your required implementations, the activities will be ready to use, either via code or [Elsa Studio](https://github.com/elsa-workflows/elsa-studio).
+
+## 🚀 Activities
+
+This extension comes with the following activities:
+
+### GenerateFakeOrders
+
+| Properties | Type | Description | Input/Output | Notes |
+| ---------- | ---- | ----------- | --- | ----- |
+| Count | int | The number of fake records to generate. | Input | Default: 10 |
+| Locale | string | The locale to use when generating fake data (e.g. 'en', 'de', 'fr', 'nl') | Input | Default: en |
+| Seed | int? | With a seed, each run will produce the identical data (for deterministic tests). | Input | - |
+
+### GenerateFakePersons
+
+| Properties | Type | Description | Input/Output | Notes |
+| ---------- | ---- | ----------- | --- | ----- |
+| Count | int | The number of fake records to generate. | Input | Default: 10 |
+| Locale | string | The locale to use when generating fake data (e.g. 'en', 'de', 'fr', 'nl') | Input | Default: en |
+| Seed | int? | With a seed, each run will produce the identical data (for deterministic tests). | Input | - |
+
+### GenerateFakeProducts
+
+| Properties | Type | Description | Input/Output | Notes |
+| ---------- | ---- | ----------- | --- | ----- |
+| Count | int | The number of fake records to generate. | Input | Default: 10 |
+| Locale | string | The locale to use when generating fake data (e.g. 'en', 'de', 'fr', 'nl') | Input | Default: en |
+| Seed | int? | With a seed, each run will produce the identical data (for deterministic tests). | Input | - |
+
+### GenerateFakeUsers
+
+| Properties | Type | Description | Input/Output | Notes |
+| ---------- | ---- | ----------- | --- | ----- |
+| Count | int | The number of fake records to generate. | Input | Default: 10 |
+| Locale | string | The locale to use when generating fake data (e.g. 'en', 'de', 'fr', 'nl') | Input | Default: en |
+| Seed | int? | With a seed, each run will produce the identical data (for deterministic tests). | Input | - |
+
+
+## 🧪 Examples
+
+### Example of your feature
+
+```csharp
+new GenerateFakeOrders
+{
+ Count = new Input(100),
+ Locale = new Input("de"),
+ Seed = new Input(42),
+}
+```
+
+---
+
+## 🚧 Limitations
+
+- Supports only a predefined set of fake data types (orders, persons, products, users).
+- Locale support is limited to a few languages (en, de, fr, nl), based on the `Bogus` library.
+
+---
+
+## 🆘 Troubleshooting
+
+### Common Errors
+
+No issues known at this time. If you encounter any problems, please open an issue with details about the error and your environment.
+
+---
+
+## 🗺️ Planned Features
+
+No further generators planned at this time, but if you have suggestions for additional fake data types or features, please let us know!
+
+---
+
+## 🗒️ Notes & Comments
+
+This extension was developed to add fake data functionality to Elsa Workflows.
+If you have ideas for improvement, encounter issues, or want to share how you're using it, feel free to open an issue or start a discussion!
\ No newline at end of file
diff --git a/src/workbench/Elsa.Server.Web/Elsa.Server.Web.csproj b/src/workbench/Elsa.Server.Web/Elsa.Server.Web.csproj
index 2e37fc91..f6724f80 100644
--- a/src/workbench/Elsa.Server.Web/Elsa.Server.Web.csproj
+++ b/src/workbench/Elsa.Server.Web/Elsa.Server.Web.csproj
@@ -60,6 +60,7 @@
+
diff --git a/src/workbench/Elsa.Server.Web/Program.cs b/src/workbench/Elsa.Server.Web/Program.cs
index af9a2e30..3ef1ffc5 100644
--- a/src/workbench/Elsa.Server.Web/Program.cs
+++ b/src/workbench/Elsa.Server.Web/Program.cs
@@ -8,6 +8,7 @@
using Elsa.DropIns.Extensions;
using Elsa.Expressions.Helpers;
using Elsa.Extensions;
+using Elsa.FakeData.Extensions;
using Elsa.Features.Services;
using Elsa.Identity.Multitenancy;
using Elsa.OpenTelemetry.Middleware;
@@ -487,6 +488,7 @@
alterations.UseMassTransitDispatcher();
}
})
+ .UseFakeData()
.UseOpenTelemetry(otel => otel.UseNewRootActivityForRemoteParent = true)
.UseWorkflowContexts();
diff --git a/src/workbench/Elsa.ServerAndStudio.Web/Elsa.ServerAndStudio.Web.csproj b/src/workbench/Elsa.ServerAndStudio.Web/Elsa.ServerAndStudio.Web.csproj
index 1d9b5aa4..47f601ee 100644
--- a/src/workbench/Elsa.ServerAndStudio.Web/Elsa.ServerAndStudio.Web.csproj
+++ b/src/workbench/Elsa.ServerAndStudio.Web/Elsa.ServerAndStudio.Web.csproj
@@ -49,6 +49,7 @@
+
diff --git a/src/workbench/Elsa.ServerAndStudio.Web/Program.cs b/src/workbench/Elsa.ServerAndStudio.Web/Program.cs
index be6a4cc9..b95cd80b 100644
--- a/src/workbench/Elsa.ServerAndStudio.Web/Program.cs
+++ b/src/workbench/Elsa.ServerAndStudio.Web/Program.cs
@@ -1,6 +1,7 @@
using Elsa.Agents;
using Elsa.Expressions.JavaScript.Libraries.Extensions;
using Elsa.Extensions;
+using Elsa.FakeData.Extensions;
using Elsa.Persistence.EFCore.Extensions;
using Elsa.Persistence.EFCore.Modules.Management;
using Elsa.Persistence.EFCore.Modules.Runtime;
@@ -139,6 +140,7 @@
.UseEmail(email => email.ConfigureOptions = options => configuration.GetSection("Smtp").Bind(options))
.UseWebhooks(webhooks => webhooks.ConfigureSinks = options => builder.Configuration.GetSection("Webhooks:Sinks").Bind(options))
.UseWorkflowsApi()
+ .UseFakeData()
.AddActivitiesFrom()
.AddWorkflowsFrom();
diff --git a/test/modules/fakedata/Elsa.FakeData.UnitTests/Activities/GenerateFakeOrdersTests.cs b/test/modules/fakedata/Elsa.FakeData.UnitTests/Activities/GenerateFakeOrdersTests.cs
new file mode 100644
index 00000000..fc893b51
--- /dev/null
+++ b/test/modules/fakedata/Elsa.FakeData.UnitTests/Activities/GenerateFakeOrdersTests.cs
@@ -0,0 +1,116 @@
+using Elsa.FakeData.Activities;
+using Elsa.FakeData.Models;
+using Elsa.Testing.Shared;
+using Elsa.Workflows.Models;
+
+namespace Elsa.FakeData.UnitTests.Activities;
+
+public class GenerateFakeOrdersTests
+{
+ [Fact]
+ public async Task Execute_WithDefaultCount_Generates10Records()
+ {
+ // Arrange
+ var result = new Output();
+ var activity = new GenerateFakeOrders { Result = result };
+
+ // Act
+ var context = await new ActivityTestFixture(activity).ExecuteAsync();
+
+ // Assert
+ var orders = context.Get(result);
+ Assert.NotNull(orders);
+ Assert.Equal(10, orders.Length);
+ }
+
+ [Theory]
+ [InlineData(1)]
+ [InlineData(5)]
+ [InlineData(25)]
+ public async Task Execute_WithCustomCount_GeneratesExpectedCount(int count)
+ {
+ // Arrange
+ var result = new Output();
+ var activity = new GenerateFakeOrders { Count = new Input(count), Result = result };
+
+ // Act
+ var context = await new ActivityTestFixture(activity).ExecuteAsync();
+
+ // Assert
+ var orders = context.Get(result);
+ Assert.NotNull(orders);
+ Assert.Equal(count, orders.Length);
+ }
+
+ [Fact]
+ public async Task Execute_WithSeed_ProducesDeterministicData()
+ {
+ const int seed = 42;
+ const int count = 5;
+
+ // Arrange
+ var result1 = new Output();
+ var activity1 = new GenerateFakeOrders
+ {
+ Count = new Input(count),
+ Seed = new Input(seed),
+ Result = result1,
+ };
+
+ var result2 = new Output();
+ var activity2 = new GenerateFakeOrders
+ {
+ Count = new Input(count),
+ Seed = new Input(seed),
+ Result = result2,
+ };
+
+ // Act
+ var context1 = await new ActivityTestFixture(activity1).ExecuteAsync();
+ var orders1 = context1.Get(result1)!.ToList();
+
+ var context2 = await new ActivityTestFixture(activity2).ExecuteAsync();
+ var orders2 = context2.Get(result2)!.ToList();
+
+ // Assert
+ Assert.Equal(orders1.Count, orders2.Count);
+ for (var i = 0; i < orders1.Count; i++)
+ {
+ Assert.Equal(orders1[i].Id, orders2[i].Id);
+ Assert.Equal(orders1[i].OrderNumber, orders2[i].OrderNumber);
+ Assert.Equal(orders1[i].CustomerEmail, orders2[i].CustomerEmail);
+ }
+ }
+
+ [Fact]
+ public async Task Execute_GeneratesOrders_WithAllPropertiesPopulated()
+ {
+ // Arrange
+ var result = new Output();
+ var activity = new GenerateFakeOrders
+ {
+ Count = new Input(5),
+ Seed = new Input(1),
+ Result = result,
+ };
+
+ // Act
+ var context = await new ActivityTestFixture(activity).ExecuteAsync();
+ var orders = context.Get(result)!;
+
+ // Assert
+ foreach (var order in orders)
+ {
+ Assert.NotEqual(Guid.Empty, order.Id);
+ Assert.False(string.IsNullOrWhiteSpace(order.OrderNumber));
+ Assert.NotEqual(default, order.OrderDate);
+ Assert.False(string.IsNullOrWhiteSpace(order.Status));
+ Assert.False(string.IsNullOrWhiteSpace(order.CustomerName));
+ Assert.False(string.IsNullOrWhiteSpace(order.CustomerEmail));
+ Assert.False(string.IsNullOrWhiteSpace(order.ShippingAddress));
+ Assert.True(order.SubTotal > 0);
+ Assert.True(order.Tax >= 0);
+ Assert.True(order.Total > 0);
+ }
+ }
+}
diff --git a/test/modules/fakedata/Elsa.FakeData.UnitTests/Activities/GenerateFakePersonsTests.cs b/test/modules/fakedata/Elsa.FakeData.UnitTests/Activities/GenerateFakePersonsTests.cs
new file mode 100644
index 00000000..b7f0c90d
--- /dev/null
+++ b/test/modules/fakedata/Elsa.FakeData.UnitTests/Activities/GenerateFakePersonsTests.cs
@@ -0,0 +1,119 @@
+using Elsa.FakeData.Activities;
+using Elsa.FakeData.Models;
+using Elsa.Testing.Shared;
+using Elsa.Workflows.Models;
+
+namespace Elsa.FakeData.UnitTests.Activities;
+
+public class GenerateFakePersonsTests
+{
+ [Fact]
+ public async Task Execute_WithDefaultCount_Generates10Records()
+ {
+ // Arrange
+ var result = new Output();
+ var activity = new GenerateFakePersons { Result = result };
+
+ // Act
+ var context = await new ActivityTestFixture(activity).ExecuteAsync();
+
+ // Assert
+ var persons = context.Get(result);
+ Assert.NotNull(persons);
+ Assert.Equal(10, persons.Length);
+ }
+
+ [Theory]
+ [InlineData(1)]
+ [InlineData(5)]
+ [InlineData(25)]
+ public async Task Execute_WithCustomCount_GeneratesExpectedCount(int count)
+ {
+ // Arrange
+ var result = new Output();
+ var activity = new GenerateFakePersons { Count = new Input(count), Result = result };
+
+ // Act
+ var context = await new ActivityTestFixture(activity).ExecuteAsync();
+
+ // Assert
+ var persons = context.Get(result);
+ Assert.NotNull(persons);
+ Assert.Equal(count, persons.Length);
+ }
+
+ [Fact]
+ public async Task Execute_WithSeed_ProducesDeterministicData()
+ {
+ const int seed = 42;
+ const int count = 5;
+
+ // Arrange
+ var result1 = new Output();
+ var activity1 = new GenerateFakePersons
+ {
+ Count = new Input(count),
+ Seed = new Input(seed),
+ Result = result1,
+ };
+
+ var result2 = new Output();
+ var activity2 = new GenerateFakePersons
+ {
+ Count = new Input(count),
+ Seed = new Input(seed),
+ Result = result2,
+ };
+
+ // Act
+ var context1 = await new ActivityTestFixture(activity1).ExecuteAsync();
+ var persons1 = context1.Get(result1)!.ToList();
+
+ var context2 = await new ActivityTestFixture(activity2).ExecuteAsync();
+ var persons2 = context2.Get(result2)!.ToList();
+
+ // Assert
+ Assert.Equal(persons1.Count, persons2.Count);
+ for (var i = 0; i < persons1.Count; i++)
+ {
+ Assert.Equal(persons1[i].Id, persons2[i].Id);
+ Assert.Equal(persons1[i].FullName, persons2[i].FullName);
+ Assert.Equal(persons1[i].Email, persons2[i].Email);
+ }
+ }
+
+ [Fact]
+ public async Task Execute_GeneratesPersons_WithAllPropertiesPopulated()
+ {
+ // Arrange
+ var result = new Output();
+ var activity = new GenerateFakePersons
+ {
+ Count = new Input(5),
+ Seed = new Input(1),
+ Result = result,
+ };
+
+ // Act
+ var context = await new ActivityTestFixture(activity).ExecuteAsync();
+ var persons = context.Get(result)!;
+
+ // Assert
+ foreach (var person in persons)
+ {
+ Assert.NotEqual(Guid.Empty, person.Id);
+ Assert.False(string.IsNullOrWhiteSpace(person.FirstName));
+ Assert.False(string.IsNullOrWhiteSpace(person.LastName));
+ Assert.False(string.IsNullOrWhiteSpace(person.FullName));
+ Assert.False(string.IsNullOrWhiteSpace(person.Email));
+ Assert.False(string.IsNullOrWhiteSpace(person.Phone));
+ Assert.NotEqual(default, person.DateOfBirth);
+ Assert.False(string.IsNullOrWhiteSpace(person.Gender));
+ Assert.False(string.IsNullOrWhiteSpace(person.Address));
+ Assert.False(string.IsNullOrWhiteSpace(person.City));
+ Assert.False(string.IsNullOrWhiteSpace(person.State));
+ Assert.False(string.IsNullOrWhiteSpace(person.ZipCode));
+ Assert.False(string.IsNullOrWhiteSpace(person.Country));
+ }
+ }
+}
diff --git a/test/modules/fakedata/Elsa.FakeData.UnitTests/Activities/GenerateFakeProductsTests.cs b/test/modules/fakedata/Elsa.FakeData.UnitTests/Activities/GenerateFakeProductsTests.cs
new file mode 100644
index 00000000..98da56d8
--- /dev/null
+++ b/test/modules/fakedata/Elsa.FakeData.UnitTests/Activities/GenerateFakeProductsTests.cs
@@ -0,0 +1,114 @@
+using Elsa.FakeData.Activities;
+using Elsa.FakeData.Models;
+using Elsa.Testing.Shared;
+using Elsa.Workflows.Models;
+
+namespace Elsa.FakeData.UnitTests.Activities;
+
+public class GenerateFakeProductsTests
+{
+ [Fact]
+ public async Task Execute_WithDefaultCount_Generates10Records()
+ {
+ // Arrange
+ var result = new Output();
+ var activity = new GenerateFakeProducts { Result = result };
+
+ // Act
+ var context = await new ActivityTestFixture(activity).ExecuteAsync();
+
+ // Assert
+ var products = context.Get(result);
+ Assert.NotNull(products);
+ Assert.Equal(10, products.Length);
+ }
+
+ [Theory]
+ [InlineData(1)]
+ [InlineData(5)]
+ [InlineData(25)]
+ public async Task Execute_WithCustomCount_GeneratesExpectedCount(int count)
+ {
+ // Arrange
+ var result = new Output();
+ var activity = new GenerateFakeProducts { Count = new Input(count), Result = result };
+
+ // Act
+ var context = await new ActivityTestFixture(activity).ExecuteAsync();
+
+ // Assert
+ var products = context.Get(result);
+ Assert.NotNull(products);
+ Assert.Equal(count, products.Length);
+ }
+
+ [Fact]
+ public async Task Execute_WithSeed_ProducesDeterministicData()
+ {
+ const int seed = 42;
+ const int count = 5;
+
+ // Arrange
+ var result1 = new Output();
+ var activity1 = new GenerateFakeProducts
+ {
+ Count = new Input(count),
+ Seed = new Input(seed),
+ Result = result1,
+ };
+
+ var result2 = new Output();
+ var activity2 = new GenerateFakeProducts
+ {
+ Count = new Input(count),
+ Seed = new Input(seed),
+ Result = result2,
+ };
+
+ // Act
+ var context1 = await new ActivityTestFixture(activity1).ExecuteAsync();
+ var products1 = context1.Get(result1)!.ToList();
+
+ var context2 = await new ActivityTestFixture(activity2).ExecuteAsync();
+ var products2 = context2.Get(result2)!.ToList();
+
+ // Assert
+ Assert.Equal(products1.Count, products2.Count);
+ for (var i = 0; i < products1.Count; i++)
+ {
+ Assert.Equal(products1[i].Id, products2[i].Id);
+ Assert.Equal(products1[i].Name, products2[i].Name);
+ Assert.Equal(products1[i].Price, products2[i].Price);
+ }
+ }
+
+ [Fact]
+ public async Task Execute_GeneratesProducts_WithAllPropertiesPopulated()
+ {
+ // Arrange
+ var result = new Output();
+ var activity = new GenerateFakeProducts
+ {
+ Count = new Input(5),
+ Seed = new Input(1),
+ Result = result,
+ };
+
+ // Act
+ var context = await new ActivityTestFixture(activity).ExecuteAsync();
+ var products = context.Get(result)!;
+
+ // Assert
+ foreach (var product in products)
+ {
+ Assert.NotEqual(Guid.Empty, product.Id);
+ Assert.False(string.IsNullOrWhiteSpace(product.Name));
+ Assert.False(string.IsNullOrWhiteSpace(product.Description));
+ Assert.True(product.Price > 0);
+ Assert.False(string.IsNullOrWhiteSpace(product.Category));
+ Assert.False(string.IsNullOrWhiteSpace(product.Department));
+ Assert.InRange(product.Rating, 1, 5);
+ Assert.True(product.Stock >= 0);
+ }
+ }
+}
diff --git a/test/modules/fakedata/Elsa.FakeData.UnitTests/Activities/GenerateFakeUsersTests.cs b/test/modules/fakedata/Elsa.FakeData.UnitTests/Activities/GenerateFakeUsersTests.cs
new file mode 100644
index 00000000..d971dfe8
--- /dev/null
+++ b/test/modules/fakedata/Elsa.FakeData.UnitTests/Activities/GenerateFakeUsersTests.cs
@@ -0,0 +1,115 @@
+using Elsa.FakeData.Activities;
+using Elsa.FakeData.Models;
+using Elsa.Testing.Shared;
+using Elsa.Workflows.Models;
+
+namespace Elsa.FakeData.UnitTests.Activities;
+
+public class GenerateFakeUsersTests
+{
+ [Fact]
+ public async Task Execute_WithDefaultCount_Generates10Records()
+ {
+ // Arrange
+ var result = new Output();
+ var activity = new GenerateFakeUsers { Result = result };
+
+ // Act
+ var context = await new ActivityTestFixture(activity).ExecuteAsync();
+
+ // Assert
+ var users = context.Get(result);
+ Assert.NotNull(users);
+ Assert.Equal(10, users.Length);
+ }
+
+ [Theory]
+ [InlineData(1)]
+ [InlineData(5)]
+ [InlineData(25)]
+ public async Task Execute_WithCustomCount_GeneratesExpectedCount(int count)
+ {
+ // Arrange
+ var result = new Output();
+ var activity = new GenerateFakeUsers { Count = new Input(count), Result = result };
+
+ // Act
+ var context = await new ActivityTestFixture(activity).ExecuteAsync();
+
+ // Assert
+ var users = context.Get(result);
+ Assert.NotNull(users);
+ Assert.Equal(count, users.Length);
+ }
+
+ [Fact]
+ public async Task Execute_WithSeed_ProducesDeterministicData()
+ {
+ const int seed = 42;
+ const int count = 5;
+
+ // Arrange
+ var result1 = new Output();
+ var activity1 = new GenerateFakeUsers
+ {
+ Count = new Input(count),
+ Seed = new Input(seed),
+ Result = result1,
+ };
+
+ var result2 = new Output();
+ var activity2 = new GenerateFakeUsers
+ {
+ Count = new Input(count),
+ Seed = new Input(seed),
+ Result = result2,
+ };
+
+ // Act
+ var context1 = await new ActivityTestFixture(activity1).ExecuteAsync();
+ var users1 = context1.Get(result1)!.ToList();
+
+ var context2 = await new ActivityTestFixture(activity2).ExecuteAsync();
+ var users2 = context2.Get(result2)!.ToList();
+
+ // Assert
+ Assert.Equal(users1.Count, users2.Count);
+ for (var i = 0; i < users1.Count; i++)
+ {
+ Assert.Equal(users1[i].Id, users2[i].Id);
+ Assert.Equal(users1[i].Username, users2[i].Username);
+ Assert.Equal(users1[i].Email, users2[i].Email);
+ }
+ }
+
+ [Fact]
+ public async Task Execute_GeneratesUsers_WithAllPropertiesPopulated()
+ {
+ // Arrange
+ var result = new Output();
+ var activity = new GenerateFakeUsers
+ {
+ Count = new Input(5),
+ Seed = new Input(1),
+ Result = result,
+ };
+
+ // Act
+ var context = await new ActivityTestFixture(activity).ExecuteAsync();
+ var users = context.Get(result)!;
+
+ // Assert
+ foreach (var user in users)
+ {
+ Assert.NotEqual(Guid.Empty, user.Id);
+ Assert.False(string.IsNullOrWhiteSpace(user.Username));
+ Assert.False(string.IsNullOrWhiteSpace(user.Email));
+ Assert.False(string.IsNullOrWhiteSpace(user.FirstName));
+ Assert.False(string.IsNullOrWhiteSpace(user.LastName));
+ Assert.False(string.IsNullOrWhiteSpace(user.Avatar));
+ Assert.NotNull(user.Roles);
+ Assert.NotEmpty(user.Roles);
+ Assert.NotEqual(default, user.CreatedAt);
+ }
+ }
+}
diff --git a/test/modules/fakedata/Elsa.FakeData.UnitTests/Elsa.FakeData.UnitTests.csproj b/test/modules/fakedata/Elsa.FakeData.UnitTests/Elsa.FakeData.UnitTests.csproj
new file mode 100644
index 00000000..fbe3b380
--- /dev/null
+++ b/test/modules/fakedata/Elsa.FakeData.UnitTests/Elsa.FakeData.UnitTests.csproj
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file