Skip to content

Commit 0392776

Browse files
Merge pull request #454 from NeoCoderMatrix86/development
Deploy v9.1
2 parents d366777 + afca18d commit 0392776

123 files changed

Lines changed: 749 additions & 872 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
name: Build & Deploy
2+
3+
on:
4+
push:
5+
branches:
6+
- development
7+
- master
8+
workflow_dispatch:
9+
10+
jobs:
11+
run-tests:
12+
uses: ./.github/workflows/run_tests.yml
13+
build:
14+
needs: run-tests
15+
runs-on: ubuntu-latest
16+
17+
steps:
18+
- uses: actions/checkout@v4
19+
20+
# version can be found here https://dotnet.microsoft.com/en-us/download/dotnet/9.0
21+
- name: Setup .NET
22+
uses: actions/setup-dotnet@v4
23+
with:
24+
dotnet-version: 9.0.x
25+
26+
- name: Install wasm-tools
27+
run: dotnet workload install wasm-tools
28+
29+
- name: Build release
30+
run: dotnet publish AudioCuesheetEditor --configuration Release --output release
31+
32+
- name: Upload Build Artifact
33+
uses: actions/upload-artifact@v4
34+
with:
35+
name: AudioCuesheetEditor-Release
36+
path: ./release
37+
38+
deploy:
39+
needs: build
40+
runs-on: ubuntu-latest
41+
environment: |-
42+
${{
43+
github.ref_name == 'master' && 'Production'
44+
|| 'Preview'
45+
}}
46+
steps:
47+
- name: Download Build Artifact
48+
uses: actions/download-artifact@v4
49+
with:
50+
name: AudioCuesheetEditor-Release
51+
- name: Deploy to Netlify
52+
uses: nwtgck/actions-netlify@v3
53+
with:
54+
publish-dir: './wwwroot'
55+
production-deploy: true
56+
fails-without-credentials: true
57+
env:
58+
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
59+
NETLIFY_SITE_ID: ${{ vars.NETLIFY_SITE_ID }}

.github/workflows/run_tests.yml

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
name: Run Tests
2+
3+
on:
4+
workflow_call:
5+
pull_request:
6+
7+
jobs:
8+
run-tests:
9+
runs-on: ubuntu-latest
10+
steps:
11+
- uses: actions/checkout@v4.2.2
12+
13+
- name: Set timestamp variable
14+
id: timestamp
15+
run: echo "datetime=$(date +'%Y-%m-%d_%H-%M-%S')" >> $GITHUB_OUTPUT
16+
17+
# version can be found here https://dotnet.microsoft.com/en-us/download/dotnet/9.0
18+
- name: Setup .NET
19+
uses: actions/setup-dotnet@v4
20+
with:
21+
dotnet-version: 9.0.x
22+
23+
- name: Install wasm-tools
24+
run: dotnet workload install wasm-tools
25+
26+
- name: Build & Install
27+
run: dotnet build
28+
- name: Ensure browsers are installed
29+
run: pwsh AudioCuesheetEditor.End2EndTests/bin/Debug/net9.0/playwright.ps1 install --with-deps
30+
31+
- name: Start App
32+
run: dotnet run --project AudioCuesheetEditor &
33+
34+
- name: Run tests
35+
run: dotnet test
36+
37+
- name: Upload traces
38+
if: always()
39+
uses: actions/upload-artifact@v4
40+
with:
41+
name: playwright-traces-${{ steps.timestamp.outputs.datetime }}
42+
path: AudioCuesheetEditor.End2EndTests/bin/Debug/net9.0/playwright-traces/
43+
if-no-files-found: ignore

.github/workflows/run_unit_tests.yml

Lines changed: 0 additions & 26 deletions
This file was deleted.
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net9.0</TargetFramework>
5+
<LangVersion>latest</LangVersion>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
<Nullable>enable</Nullable>
8+
<EnableMSTestRunner>true</EnableMSTestRunner>
9+
<OutputType>Exe</OutputType>
10+
<TestingPlatformDotnetTestSupport>true</TestingPlatformDotnetTestSupport>
11+
<!--
12+
Displays error on console in addition to the log file. Note that this feature comes with a performance impact.
13+
For more information, visit https://learn.microsoft.com/dotnet/core/testing/unit-testing-platform-integration-dotnet-test#show-failure-per-test
14+
-->
15+
<TestingPlatformShowTestsFailure>true</TestingPlatformShowTestsFailure>
16+
</PropertyGroup>
17+
18+
<ItemGroup>
19+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.0" />
20+
<PackageReference Include="Microsoft.Playwright.MSTest" Version="1.52.0" />
21+
<PackageReference Include="Microsoft.Testing.Extensions.CodeCoverage" Version="17.14.2" />
22+
<PackageReference Include="Microsoft.Testing.Extensions.TrxReport" Version="1.7.0" />
23+
<PackageReference Include="MSTest" Version="3.9.0" />
24+
</ItemGroup>
25+
26+
<ItemGroup>
27+
<Using Include="Microsoft.VisualStudio.TestTools.UnitTesting" />
28+
</ItemGroup>
29+
30+
<ItemGroup>
31+
<None Update="Kalimba.mp3">
32+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
33+
</None>
34+
<None Update="Sample_Cuesheet.cue">
35+
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
36+
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
37+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
38+
</None>
39+
<None Update="Sample_Inputfile.txt">
40+
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
41+
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
42+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
43+
</None>
44+
<None Update="Sample_Project.ace">
45+
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
46+
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
47+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
48+
</None>
49+
</ItemGroup>
50+
51+
</Project>
8.02 MB
Binary file not shown.
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
using Microsoft.Playwright;
2+
using Microsoft.Playwright.MSTest;
3+
4+
namespace AudioCuesheetEditor.End2EndTests.Pages
5+
{
6+
[TestClass]
7+
public class AboutTest : PageTest
8+
{
9+
[TestInitialize]
10+
public async Task TestInitializeAsync()
11+
{
12+
await Context.Tracing.StartAsync(new()
13+
{
14+
Title = $"{TestContext.FullyQualifiedTestClassName}.{TestContext.TestName}",
15+
Screenshots = true,
16+
Snapshots = true,
17+
Sources = true
18+
});
19+
}
20+
21+
[TestCleanup]
22+
public async Task TestCleanupAsync()
23+
{
24+
var failed = new[] { UnitTestOutcome.Failed, UnitTestOutcome.Error, UnitTestOutcome.Timeout, UnitTestOutcome.Aborted }.Contains(TestContext.CurrentTestOutcome);
25+
26+
await Context.Tracing.StopAsync(new()
27+
{
28+
Path = failed ? Path.Combine(
29+
Environment.CurrentDirectory,
30+
"playwright-traces",
31+
$"{TestContext.FullyQualifiedTestClassName}.{TestContext.TestName}.zip"
32+
) : null,
33+
});
34+
}
35+
36+
[TestMethod]
37+
public async Task HasTitleAsync()
38+
{
39+
await Page.GotoAsync("http://localhost:5132/about");
40+
await Expect(Page).ToHaveTitleAsync("AudioCuesheetEditor");
41+
await Expect(Page.GetByRole(AriaRole.Heading, new() { Name = "About AudioCuesheetEditor" })).ToBeVisibleAsync();
42+
}
43+
}
44+
}
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
using Microsoft.Playwright;
2+
using Microsoft.Playwright.MSTest;
3+
using System.Text.RegularExpressions;
4+
5+
namespace AudioCuesheetEditor.End2EndTests.Pages
6+
{
7+
[TestClass]
8+
public class IndexTest : PageTest
9+
{
10+
[TestInitialize]
11+
public async Task TestInitializeAsync()
12+
{
13+
await Context.Tracing.StartAsync(new()
14+
{
15+
Title = $"{TestContext.FullyQualifiedTestClassName}.{TestContext.TestName}",
16+
Screenshots = true,
17+
Snapshots = true,
18+
Sources = true
19+
});
20+
}
21+
22+
[TestCleanup]
23+
public async Task TestCleanupAsync()
24+
{
25+
var failed = new[] { UnitTestOutcome.Failed, UnitTestOutcome.Error, UnitTestOutcome.Timeout, UnitTestOutcome.Aborted }.Contains(TestContext.CurrentTestOutcome);
26+
27+
await Context.Tracing.StopAsync(new()
28+
{
29+
Path = failed ? Path.Combine(
30+
Environment.CurrentDirectory,
31+
"playwright-traces",
32+
$"{TestContext.FullyQualifiedTestClassName}.{TestContext.TestName}.zip"
33+
) : null,
34+
});
35+
}
36+
37+
[TestMethod]
38+
public async Task HasTitleAsync()
39+
{
40+
await Page.GotoAsync("http://localhost:5132/");
41+
await Expect(Page).ToHaveTitleAsync("AudioCuesheetEditor");
42+
await Expect(Page.GetByRole(AriaRole.Button, new() { Name = "AudioCuesheetEditor" })).ToBeVisibleAsync();
43+
}
44+
45+
[TestMethod]
46+
public async Task CheckSettingsAsync()
47+
{
48+
await Page.GotoAsync("http://localhost:5132/");
49+
await Page.GetByRole(AriaRole.Toolbar).GetByRole(AriaRole.Button).Filter(new() { HasTextRegex = new Regex("^$") }).Nth(3).ClickAsync();
50+
await Page.Locator("div").Filter(new() { HasTextRegex = new Regex("^Settings$") }).ClickAsync();
51+
await Expect(Page.GetByRole(AriaRole.Heading, new() { Name = "Settings" })).ToBeVisibleAsync();
52+
}
53+
54+
[TestMethod]
55+
public async Task RecordAsync()
56+
{
57+
await Page.GotoAsync("http://localhost:5132/");
58+
await Page.GetByText("Record view").ClickAsync();
59+
await Page.GetByRole(AriaRole.Button, new() { Name = "Start recording" }).ClickAsync();
60+
await Page.GetByRole(AriaRole.Textbox, new() { Name = "Artist", Exact = true }).ClickAsync();
61+
await Page.GetByRole(AriaRole.Textbox, new() { Name = "Artist", Exact = true }).FillAsync("Test Track 1 Artist");
62+
await Page.GetByRole(AriaRole.Textbox, new() { Name = "Artist", Exact = true }).PressAsync("Tab");
63+
await Page.GetByRole(AriaRole.Textbox, new() { Name = "Title", Exact = true }).FillAsync("Test Track 1 Title");
64+
await Page.GetByRole(AriaRole.Textbox, new() { Name = "Title", Exact = true }).PressAsync("Tab");
65+
await Page.GetByRole(AriaRole.Button, new() { Name = "Add track" }).ClickAsync();
66+
await Page.GetByRole(AriaRole.Textbox, new() { Name = "Artist", Exact = true }).FillAsync("Test Track 2 Artist");
67+
await Page.GetByRole(AriaRole.Textbox, new() { Name = "Artist", Exact = true }).PressAsync("Tab");
68+
await Page.GetByRole(AriaRole.Textbox, new() { Name = "Title", Exact = true }).FillAsync("Test Track 2 Title");
69+
await Page.GetByRole(AriaRole.Textbox, new() { Name = "Title", Exact = true }).PressAsync("Tab");
70+
await Page.GetByRole(AriaRole.Button, new() { Name = "Add track" }).ClickAsync();
71+
await Page.GetByRole(AriaRole.Button, new() { Name = "Stop recording" }).ClickAsync();
72+
await Expect(Page.GetByRole(AriaRole.Cell, new() { Name = "Test Track 1 Artist Clear" })).ToBeVisibleAsync();
73+
await Expect(Page.GetByRole(AriaRole.Cell, new() { Name = "Test Track 1 Title Clear" })).ToBeVisibleAsync();
74+
await Expect(Page.GetByRole(AriaRole.Cell, new() { Name = "Test Track 2 Artist Clear" })).ToBeVisibleAsync();
75+
await Expect(Page.GetByRole(AriaRole.Cell, new() { Name = "Test Track 2 Title Clear" })).ToBeVisibleAsync();
76+
}
77+
78+
[TestMethod]
79+
public async Task ImportAsync()
80+
{
81+
await Page.GotoAsync("http://localhost:5132/");
82+
await Page.GetByText("Import view").ClickAsync();
83+
await Page.GetByRole(AriaRole.Button, new() { Name = "Choose File" }).SetInputFilesAsync(new[] { "Sample_Inputfile.txt" });
84+
await Page.GetByRole(AriaRole.Button, new() { Name = "Complete" }).ClickAsync();
85+
await Expect(Page.GetByRole(AriaRole.Cell, new() { Name = "Sample Artist 1 Clear" })).ToBeVisibleAsync();
86+
await Expect(Page.GetByRole(AriaRole.Cell, new() { Name = ":20:13" }).Nth(1)).ToBeVisibleAsync();
87+
await Expect(Page.GetByRole(AriaRole.Textbox, new() { Name = "Cuesheet artist" })).ToHaveValueAsync("CuesheetArtist");
88+
await Page.GetByRole(AriaRole.Textbox, new() { Name = "Cuesheet title" }).ClickAsync();
89+
await Expect(Page.GetByRole(AriaRole.Group).Filter(new() { HasText = "AudiofileAudiofile Search" }).Locator("input[type=\"file\"]")).ToBeEmptyAsync();
90+
await Page.GetByText("Import view").ClickAsync();
91+
await Expect(Page.GetByText("PreviousNext")).ToBeVisibleAsync();
92+
}
93+
94+
[TestMethod]
95+
public async Task ChangeLanguageAsync()
96+
{
97+
await Page.GotoAsync("http://localhost:5132/");
98+
await Page.GetByRole(AriaRole.Button, new() { Name = "Change language" }).ClickAsync();
99+
await Page.GetByText("German (Germany)").ClickAsync();
100+
await Expect(Page.GetByRole(AriaRole.Heading, new() { Name = "Abschnitte" })).ToBeVisibleAsync();
101+
await Expect(Page.GetByRole(AriaRole.Heading, new() { Name = "Allgemeine Informationen" })).ToBeVisibleAsync();
102+
await Expect(Page.GetByText("Aufnahmeansicht")).ToBeVisibleAsync();
103+
await Expect(Page.GetByRole(AriaRole.Heading, new() { Name = "Titel" })).ToBeVisibleAsync();
104+
await Expect(Page.GetByRole(AriaRole.Heading, new() { Name = "Wiedergabe" })).ToBeVisibleAsync();
105+
}
106+
107+
[TestMethod]
108+
public async Task OpenSampleCuesheetAsync()
109+
{
110+
await Page.GotoAsync("http://localhost:5132/");
111+
await Page.GetByRole(AriaRole.Button, new() { Name = "File", Exact = true }).ClickAsync();
112+
await Page.Locator("div").Filter(new() { HasTextRegex = new Regex("^Open$") }).ClickAsync();
113+
await Page.Locator("#dropFileInputId_SelectFileDialog").GetByRole(AriaRole.Button, new() { Name = "Choose File" }).ClickAsync();
114+
await Page.Locator("#dropFileInputId_SelectFileDialog").GetByRole(AriaRole.Button, new() { Name = "Choose File" }).SetInputFilesAsync(new[] { "Sample_Cuesheet.cue" });
115+
await Expect(Page.GetByRole(AriaRole.Textbox, new() { Name = "Cuesheet artist" })).ToHaveValueAsync("Sample CD Artist");
116+
await Expect(Page.GetByRole(AriaRole.Textbox, new() { Name = "Cuesheet title" })).ToHaveValueAsync("Sample CD Title");
117+
await Expect(Page.GetByRole(AriaRole.Cell, new() { Name = "Sample Artist 3 Clear" })).ToBeVisibleAsync();
118+
await Expect(Page.GetByRole(AriaRole.Cell, new() { Name = ":45:54" }).Nth(1)).ToBeVisibleAsync();
119+
await Page.GetByRole(AriaRole.Toolbar).GetByRole(AriaRole.Button).Filter(new() { HasTextRegex = new Regex("^$") }).First.ClickAsync();
120+
await Expect(Page.GetByRole(AriaRole.Paragraph).Filter(new() { HasText = "Tracks has invalid Count (0)!" })).ToBeVisibleAsync();
121+
}
122+
123+
[TestMethod]
124+
public async Task OpenProjectFileAsync()
125+
{
126+
await Page.GotoAsync("http://localhost:5132/");
127+
await Page.GetByRole(AriaRole.Button, new() { Name = "File", Exact = true }).ClickAsync();
128+
await Page.Locator("div").Filter(new() { HasTextRegex = new Regex("^Open$") }).ClickAsync();
129+
await Page.Locator("#dropFileInputId_SelectFileDialog").GetByRole(AriaRole.Button, new() { Name = "Choose File" }).ClickAsync();
130+
await Page.Locator("#dropFileInputId_SelectFileDialog").GetByRole(AriaRole.Button, new() { Name = "Choose File" }).SetInputFilesAsync(new[] { "Sample_Project.ace" });
131+
await Expect(Page.GetByRole(AriaRole.Textbox, new() { Name = "Cuesheet artist" })).ToHaveValueAsync("Sample CD Artist");
132+
await Expect(Page.GetByRole(AriaRole.Textbox, new() { Name = "Cuesheet title" })).ToHaveValueAsync("Sample CD Title");
133+
await Expect(Page.GetByRole(AriaRole.Cell, new() { Name = "Sample Title 2 Clear" })).ToBeVisibleAsync();
134+
await Expect(Page.GetByRole(AriaRole.Cell, new() { Name = ":09:23" }).Nth(1)).ToBeVisibleAsync();
135+
await Expect(Page.GetByRole(AriaRole.Cell, new() { Name = ":45:54" }).First).ToBeVisibleAsync();
136+
await Page.GetByRole(AriaRole.Toolbar).GetByRole(AriaRole.Button).Filter(new() { HasTextRegex = new Regex("^$") }).First.ClickAsync();
137+
await Expect(Page.GetByRole(AriaRole.Paragraph).Filter(new() { HasText = "Tracks has invalid Count (0)!" })).ToBeVisibleAsync();
138+
}
139+
140+
[TestMethod]
141+
public async Task RenameAudiofileTestAsync()
142+
{
143+
await Page.GotoAsync("http://localhost:5132/");
144+
await Page.GetByRole(AriaRole.Group).Filter(new() { HasText = "AudiofileAudiofile Search" }).GetByRole(AriaRole.Button).Nth(3).ClickAsync();
145+
await Expect(Page.GetByText("Download file Rename file")).ToMatchAriaSnapshotAsync("- paragraph: Download file\n- paragraph: Rename file");
146+
await Page.Locator("[id^='overlay']").ClickAsync();
147+
await Page.GetByRole(AriaRole.Group).Filter(new() { HasText = "AudiofileAudiofile Search" }).Locator("input[type=\"file\"]").ClickAsync();
148+
await Page.GetByRole(AriaRole.Group).Filter(new() { HasText = "AudiofileAudiofile Search" }).Locator("input[type=\"file\"]").SetInputFilesAsync(new[] { "Kalimba.mp3" });
149+
await Page.GetByRole(AriaRole.Group).Filter(new() { HasText = "AudiofileAudiofile Search" }).GetByRole(AriaRole.Button).Nth(3).ClickAsync();
150+
await Expect(Page.GetByText("Download file Rename file")).ToMatchAriaSnapshotAsync("- paragraph: Download file\n- paragraph: Rename file");
151+
await Page.GetByText("Rename file").ClickAsync();
152+
await Page.GetByRole(AriaRole.Textbox, new() { Name = "New file name" }).FillAsync("Kalimba test 123.mp3");
153+
await Page.GetByRole(AriaRole.Button, new() { Name = "Ok" }).ClickAsync();
154+
await Expect(Page.Locator("#app")).ToMatchAriaSnapshotAsync("- textbox \"Cuesheet artist\"\n- group \"Cuesheet artist\"\n- text: Cuesheet artist\n- textbox \"Cuesheet title\"\n- group \"Cuesheet title\"\n- text: Cuesheet title\n- group:\n - button \"Choose File\"\n - textbox \"Audiofile\": /Kalimba test \\d+\\.mp3/\n - group \"Audiofile\"\n - text: Audiofile\n - button \"Search\"\n - button\n - button\n- group:\n - button \"Choose File\"\n - textbox \"CD Textfile\": No file selected\n - group \"CD Textfile\"\n - text: CD Textfile\n - button \"Search\"\n - button [disabled]\n - button\n- textbox \"Cataloguenumber\"\n- group \"Cataloguenumber\"\n- text: Cataloguenumber");
155+
}
156+
}
157+
}

AudioCuesheetEditor/wwwroot/samples/Sample_Cuesheet.cue renamed to AudioCuesheetEditor.End2EndTests/Sample_Cuesheet.cue

File renamed without changes.

AudioCuesheetEditor/wwwroot/samples/Sample_Inputfile.txt renamed to AudioCuesheetEditor.End2EndTests/Sample_Inputfile.txt

File renamed without changes.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"Tracks":[{"Position":1,"Artist":"Sample Artist 1","Title":"Sample Title 1","Begin":"00:00:00","End":"00:05:00","Flags":[],"IsLinkedToPreviousTrack":false},{"Position":2,"Artist":"Sample Artist 2","Title":"Sample Title 2","Begin":"00:05:00","End":"00:09:23","Flags":[],"IsLinkedToPreviousTrack":false},{"Position":3,"Artist":"Sample Artist 3","Title":"Sample Title 3","Begin":"00:09:23","End":"00:15:54","Flags":[],"IsLinkedToPreviousTrack":false},{"Position":4,"Artist":"Sample Artist 4","Title":"Sample Title 4","Begin":"00:15:54","End":"00:20:13","Flags":[],"IsLinkedToPreviousTrack":false},{"Position":5,"Artist":"Sample Artist 5","Title":"Sample Title 5","Begin":"00:20:13","End":"00:24:54","Flags":[],"IsLinkedToPreviousTrack":false},{"Position":6,"Artist":"Sample Artist 6","Title":"Sample Title 6","Begin":"00:24:54","End":"00:31:54","Flags":[],"IsLinkedToPreviousTrack":false},{"Position":7,"Artist":"Sample Artist 7","Title":"Sample Title 7","Begin":"00:31:54","End":"00:45:54","Flags":[],"IsLinkedToPreviousTrack":false},{"Position":8,"Artist":"Sample Artist 8","Title":"Sample Title 8","Begin":"00:45:54","Flags":[],"IsLinkedToPreviousTrack":false}],"Artist":"Sample CD Artist","Title":"Sample CD Title","Audiofile":{"Name":"Sample.mp3"},"Sections":[]}

0 commit comments

Comments
 (0)