Skip to content

Commit fe0badf

Browse files
authored
Added basic e2e test setup (#44)
* Added basic e2e test setup
1 parent 52216cc commit fe0badf

13 files changed

Lines changed: 487 additions & 97 deletions

File tree

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,5 @@
2525
/src/NodeDev.Core.Types.Tests/bin
2626
/src/NodeDev.Core.Types.Tests/obj
2727
/src/NodeDev.Core.Types/bin
28+
/src/NodeDev.EndToEndTests/bin/Debug/net8.0
29+
/src/NodeDev.EndToEndTests/obj

src/NodeDev.Blazor/Components/ClassExplorer.razor

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
@inject IDialogService DialogService
22

3-
<MudStack Row="false" Class="wh100">
3+
<MudStack Row="false" Class="wh100" data-test-id="classExplorer">
44
<MudText>@Class.Name</MudText>
55

66
<MudTreeView T="TreeItem" Items="Items" SelectedValueChanged="OnSelectedItemChanged" Dense="true" Class="w100">
@@ -19,7 +19,7 @@
1919
{
2020
<MudTreeViewItem @bind-Expanded="@context.Expanded" Items="@context.Children" Value="@context.Value" Text="@context.Value!.Name" EndTextTypo="@Typo.caption">
2121
<BodyContent Context="Item">
22-
<div style="display: grid; grid-template-columns: 1fr auto; align-items: center; width: 100%" @onmouseover="() => Hovered = Item.Value" @onmouseout="() => Hovered = null">
22+
<div style="display: grid; grid-template-columns: 1fr auto; align-items: center; width: 100%" @onmouseover="() => Hovered = Item.Value" @onmouseout="() => Hovered = null" data-test-id="@context.Value.Type">
2323
<MudText Style="justify-self: start;">@Item.Text</MudText>
2424
<div style="@($"justify-self: end; visibility: {(Hovered == Item.Value ? "visible" : "hidden")}")">
2525
<MudIconButton Icon="@Icons.Material.Filled.Add" Size="Size.Medium" Color="Color.Inherit" OnClick="context.Value.Type == TreeItemType.MethodsFolder ? ShowAddMethodMenu : ShowNewProperty" />
@@ -32,7 +32,7 @@
3232
{
3333
<MudTreeViewItem @bind-Expanded="@context.Expanded" Value="@context.Value" Text="@context.Value!.Name" EndTextTypo="@Typo.caption">
3434
<BodyContent Context="Item">
35-
<div style="display: grid; grid-template-columns: 1fr auto; align-items: center; width: 100%" @onmouseover="() => Hovered = Item.Value" @onmouseout="() => Hovered = null">
35+
<div style="display: grid; grid-template-columns: 1fr auto; align-items: center; width: 100%" @onmouseover="() => Hovered = Item.Value" @onmouseout="() => Hovered = null" data-test-id="Method" data-test-method="@Item.Text">
3636
<MudText Typo="Typo.caption" Style="justify-self: start;">@Item.Value!.Method!.ReturnType.FriendlyName @Item.Text (@string.Join(',', Item.Value.Method!.Parameters.Select(x => $"{x.ParameterType.FriendlyName} {x.Name}")))</MudText>
3737
<div style="@($"justify-self: end; visibility: {(Hovered == Item.Value ? "visible" : "hidden")}")">
3838
<MudIconButton Icon="@Icons.Material.Filled.Edit" Size="Size.Medium" Color="Color.Inherit" OnClick="() => ShowMethodEdit(Item.Value!)" />
@@ -46,7 +46,7 @@
4646
{
4747
<MudTreeViewItem @bind-Expanded="@context.Expanded" Value="@context.Value" Text="@context.Value.Name" EndTextTypo="@Typo.caption">
4848
<BodyContent Context="Item">
49-
<div style="display: grid; grid-template-columns: 1fr auto; align-items: center; width: 100%" @onmouseover="() => Hovered = Item.Value" @onmouseout="() => Hovered = null">
49+
<div style="display: grid; grid-template-columns: 1fr auto; align-items: center; width: 100%" @onmouseover="() => Hovered = Item.Value" @onmouseout="() => Hovered = null" data-test-id="Property">
5050
<MudText Typo="Typo.caption" Style="justify-self: start;">@Item.Value!.Property!.PropertyType.FriendlyName @Item.Value!.Name</MudText>
5151
<div style="@($"justify-self: end; visibility: {(Hovered == Item.Value ? "visible" : "hidden")}")">
5252
<MudIconButton Icon="@Icons.Material.Filled.ShapeLine" Size="Size.Medium" Color="Color.Inherit" OnClick="() => ShowPropertyTypeEdit(Item.Value!)" />
Lines changed: 91 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -1,98 +1,99 @@
11

22
<MudStack Row="false" Class="wh100">
3-
<MudText>Project</MudText>
4-
5-
<MudTreeView T="TreeItem" Items="Items" @bind-SelectedValue="Selected" @bind-SelectedValue:after="OnSelectedItemChanged" Class="flex-1">
6-
<ItemTemplate>
7-
@if (context.Value == null)
8-
{ }
9-
else if (context.Value.Type == TreeItemType.Folder)
10-
{
11-
<MudTreeViewItem @bind-Expanded="@context.Expanded" Items="@context.Children" Value="@context.Value" Text="@context.Value.Name" EndTextTypo="@Typo.caption" />
12-
}
13-
else if (context.Value.Type == TreeItemType.Class)
14-
{
15-
<MudTreeViewItem @bind-Expanded="@context.Expanded" Value="@context.Value" Text="@context.Value.Name" EndTextTypo="@Typo.caption" />
16-
}
17-
</ItemTemplate>
18-
</MudTreeView>
3+
<MudText>Project</MudText>
4+
5+
<MudTreeView T="TreeItem" Items="Items" @bind-SelectedValue="Selected" @bind-SelectedValue:after="OnSelectedItemChanged" Class="flex-1" data-test-id="projectExplorer">
6+
<ItemTemplate>
7+
@if (context.Value == null)
8+
{ }
9+
else if (context.Value.Type == TreeItemType.Folder)
10+
{
11+
<MudTreeViewItem @bind-Expanded="@context.Expanded" Items="@context.Children" Value="@context.Value" Text="@context.Value.Name" EndTextTypo="@Typo.caption" data-test-id="projectExplorerMethod" />
12+
}
13+
else if (context.Value.Type == TreeItemType.Class)
14+
{
15+
<MudTreeViewItem @bind-Expanded="@context.Expanded" Value="@context.Value" Text="@context.Value.Name" EndTextTypo="@Typo.caption" data-test-id="projectExplorerClass" />
16+
}
17+
</ItemTemplate>
18+
</MudTreeView>
1919
</MudStack>
2020

2121
@code {
2222

23-
private enum TreeItemType
24-
{
25-
Folder,
26-
Class
27-
}
28-
29-
private record class TreeItem(string Name, TreeItemType Type, NodeDev.Core.Class.NodeClass? Class)
30-
{
31-
public bool IsExpanded { get; set; } = true;
32-
}
33-
34-
[Parameter]
35-
public NodeDev.Core.Project Project { get; set; } = null!;
36-
37-
[Parameter]
38-
public NodeDev.Core.Class.NodeClass? SelectedClass { get; set; }
39-
40-
[Parameter]
41-
public EventCallback<NodeDev.Core.Class.NodeClass?> SelectedClassChanged { get; set; }
42-
43-
private TreeItem? Selected = null;
44-
45-
private List<TreeItemData<TreeItem>> Items { get; } = new();
46-
47-
private void OnSelectedItemChanged()
48-
{
49-
if (Selected?.Type == TreeItemType.Class)
50-
{
51-
SelectedClass = Selected.Class;
52-
_ = SelectedClassChanged.InvokeAsync(SelectedClass);
53-
}
54-
else
55-
{
56-
SelectedClass = null;
57-
_ = SelectedClassChanged.InvokeAsync(SelectedClass);
58-
}
59-
}
60-
61-
protected override void OnInitialized()
62-
{
63-
base.OnInitialized();
64-
65-
foreach (var nodeClass in Project.Classes)
66-
AddClass(nodeClass);
67-
}
68-
69-
private void AddClass(NodeDev.Core.Class.NodeClass nodeClass)
70-
{
71-
// find the folder that already exists in the tree
72-
var folders = nodeClass.Namespace.Split('.');
73-
TreeItemData<TreeItem>? folder = null;
74-
for (int i = 0; i < folders.Length; ++i)
75-
{
76-
var parent = folder?.Children ?? Items;
77-
folder = parent.FirstOrDefault(x => x.Value?.Name == folders[i] && x.Value?.Type == TreeItemType.Folder);
78-
if (folder == null)
79-
{
80-
folder = new TreeItemData<TreeItem>()
81-
{
82-
Value = new(folders[i], TreeItemType.Folder, null),
83-
Children = []
84-
};
85-
parent.Add(folder);
86-
}
87-
}
88-
89-
if (folder?.Children == null)
90-
throw new Exception("Call cannot have no namespace ??");
91-
92-
folder.Children.Add(new()
93-
{
94-
Value = new(nodeClass.Name, TreeItemType.Class, nodeClass)
95-
});
96-
}
23+
private enum TreeItemType
24+
{
25+
Folder,
26+
Class
27+
}
28+
29+
private record class TreeItem(string Name, TreeItemType Type, NodeDev.Core.Class.NodeClass? Class)
30+
{
31+
public bool IsExpanded { get; set; } = true;
32+
}
33+
34+
[Parameter]
35+
public NodeDev.Core.Project Project { get; set; } = null!;
36+
37+
[Parameter]
38+
public NodeDev.Core.Class.NodeClass? SelectedClass { get; set; }
39+
40+
[Parameter]
41+
public EventCallback<NodeDev.Core.Class.NodeClass?> SelectedClassChanged { get; set; }
42+
43+
private TreeItem? Selected = null;
44+
45+
private List<TreeItemData<TreeItem>> Items { get; } = new();
46+
47+
private void OnSelectedItemChanged()
48+
{
49+
if (Selected?.Type == TreeItemType.Class)
50+
{
51+
SelectedClass = Selected.Class;
52+
_ = SelectedClassChanged.InvokeAsync(SelectedClass);
53+
}
54+
else
55+
{
56+
SelectedClass = null;
57+
_ = SelectedClassChanged.InvokeAsync(SelectedClass);
58+
}
59+
}
60+
61+
protected override void OnInitialized()
62+
{
63+
base.OnInitialized();
64+
65+
foreach (var nodeClass in Project.Classes)
66+
AddClass(nodeClass);
67+
}
68+
69+
private void AddClass(NodeDev.Core.Class.NodeClass nodeClass)
70+
{
71+
// find the folder that already exists in the tree
72+
var folders = nodeClass.Namespace.Split('.');
73+
TreeItemData<TreeItem>? folder = null;
74+
for (int i = 0; i < folders.Length; ++i)
75+
{
76+
var parent = folder?.Children ?? Items;
77+
folder = parent.FirstOrDefault(x => x.Value?.Name == folders[i] && x.Value?.Type == TreeItemType.Folder);
78+
if (folder == null)
79+
{
80+
folder = new TreeItemData<TreeItem>()
81+
{
82+
Value = new(folders[i], TreeItemType.Folder, null),
83+
Children = [],
84+
Expanded = true
85+
};
86+
parent.Add(folder);
87+
}
88+
}
89+
90+
if (folder?.Children == null)
91+
throw new Exception("Call cannot have no namespace ??");
92+
93+
folder.Children.Add(new()
94+
{
95+
Value = new(nodeClass.Name, TreeItemType.Class, nodeClass)
96+
});
97+
}
9798

9899
}

src/NodeDev.Blazor/Index.razor

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
@inject Services.DebuggedPathService DebuggedPathService
2+
@inject NavigationManager NavigationManager
3+
@inject ISnackbar Snackbar
24

35
<MudThemeProvider />
46
<MudPopoverProvider />
57
<MudDialogProvider />
68
<MudSnackbarProvider />
79

810
<MudLayout Style="height: 100vh; width: 100%; overflow: hidden">
9-
<MudAppBar Elevation="1">
10-
<MudButton OnClick="Save" Class="ml-3">Save</MudButton>
11+
<MudAppBar Elevation="1" data-test-id="appBar">
12+
<MudButton OnClick="NewProject" Class="ml-3" data-test-id="newProject">New Project</MudButton>
13+
<MudButton OnClick="Save" Class="ml-3" data-test-id="Save">Save</MudButton>
1114
<MudButton OnClick="Add" Class="ml-3">Add node</MudButton>
1215
<MudButton OnClick="Run" Class="ml-3">Run</MudButton>
1316
<MudButton OnClick="SwitchLiveDebugging">@(Project.IsLiveDebuggingEnabled ? "Stop Live Debugging" : "Start Live Debugging")</MudButton>
@@ -18,7 +21,7 @@
1821

1922
<MudExtensions.MudSplitter EnableSlide="true" Sensitivity="0.01" @bind-Dimension="ProjectExplorerGraphPercentage" Class="wh100 overflow-hidden relative">
2023
<StartContent>
21-
<MudTabs Elevation="2" Rounded="true" ApplyEffectsToContainer="true" PanelClass="pa-2 wh100" KeepPanelsAlive="true" Class="wh100">
24+
<MudTabs Elevation="2" Rounded="true" ApplyEffectsToContainer="true" PanelClass="pa-2 wh100" KeepPanelsAlive="true" Class="wh100" data-test-id="ProjectExplorerSection">
2225
<MudTabPanel Text="Project">
2326
<ProjectExplorer Project="Project" @bind-SelectedClass="SelectedClass"></ProjectExplorer>
2427
</MudTabPanel>
@@ -164,6 +167,17 @@
164167
{
165168
var content = Project.Serialize();
166169
File.WriteAllText("project.json", content);
170+
171+
Snackbar.Add("Project saved", Severity.Success);
172+
}
173+
174+
private void NewProject()
175+
{
176+
if (File.Exists("project.json"))
177+
File.Move("project.json", "project_backup.json", true);
178+
179+
180+
NavigationManager.Refresh(true);
167181
}
168182

169183
private void Add()
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
Feature: Save a project to file system
2+
3+
Scenario: Save empty project
4+
Given I load the default project
5+
Then The 'Main' method in the 'Program' class should exist
6+
7+
Given I save the current project
8+
Then Snackbar should contain 'Project saved'

src/NodeDev.EndToEndTests/Features/SaveProject.feature.cs

Lines changed: 112 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)