From c9fe389ef84c7efe4bd3aca9faf54edd956b47e4 Mon Sep 17 00:00:00 2001 From: ShiosOS Date: Sun, 8 Mar 2026 04:31:52 -0400 Subject: [PATCH 1/5] Add initial test suite for leftovers --- .../Cauldron.Api.Tests.csproj | 22 +++++ .../LeftoverEndpointsTests.cs | 87 +++++++++++++++++++ .../TestApplicationFactory.cs | 32 +++++++ backend/Cauldron.Api.Tests/Usings.cs | 1 + backend/Cauldron.Api/Cauldron.Api.sln | 29 +++++++ backend/Cauldron.Api/Program.cs | 2 + frontend/cauldron/e2e/vue.spec.ts | 86 ++++++++++++++++-- frontend/cauldron/src/__tests__/App.spec.ts | 16 +++- .../src/__tests__/LeftoverForm.spec.ts | 48 ++++++++++ .../src/__tests__/leftover.service.spec.ts | 37 ++++++++ frontend/cauldron/src/services/leftover.ts | 6 +- 11 files changed, 354 insertions(+), 12 deletions(-) create mode 100644 backend/Cauldron.Api.Tests/Cauldron.Api.Tests.csproj create mode 100644 backend/Cauldron.Api.Tests/LeftoverEndpointsTests.cs create mode 100644 backend/Cauldron.Api.Tests/TestApplicationFactory.cs create mode 100644 backend/Cauldron.Api.Tests/Usings.cs create mode 100644 frontend/cauldron/src/__tests__/LeftoverForm.spec.ts create mode 100644 frontend/cauldron/src/__tests__/leftover.service.spec.ts diff --git a/backend/Cauldron.Api.Tests/Cauldron.Api.Tests.csproj b/backend/Cauldron.Api.Tests/Cauldron.Api.Tests.csproj new file mode 100644 index 0000000..da78013 --- /dev/null +++ b/backend/Cauldron.Api.Tests/Cauldron.Api.Tests.csproj @@ -0,0 +1,22 @@ + + + + net10.0 + enable + enable + false + + + + + + + + + + + + + + + diff --git a/backend/Cauldron.Api.Tests/LeftoverEndpointsTests.cs b/backend/Cauldron.Api.Tests/LeftoverEndpointsTests.cs new file mode 100644 index 0000000..046a0c5 --- /dev/null +++ b/backend/Cauldron.Api.Tests/LeftoverEndpointsTests.cs @@ -0,0 +1,87 @@ +using System.Net; +using System.Net.Http.Json; +using Cauldron.Api.Contracts.Leftovers; + +namespace Cauldron.Api.Tests; + +public class LeftoverEndpointsTests(TestApplicationFactory factory) : IClassFixture +{ + private readonly HttpClient _client = factory.CreateClient(); + + [Fact] + public async Task CreateLeftover_PersistsAndCanBeFetched() + { + var today = DateOnly.FromDateTime(DateTime.UtcNow); + + var request = new CreateLeftoverRequest( + "Chili", + today, + today.AddDays(2), + 4, + "Medium heat", + DateTime.UtcNow); + + var createResponse = await _client.PostAsJsonAsync("/api/leftovers", request); + + Assert.Equal(HttpStatusCode.Created, createResponse.StatusCode); + + var created = await createResponse.Content.ReadFromJsonAsync(); + + Assert.NotNull(created); + Assert.True(created.Id > 0); + Assert.Equal(request.Name, created.Name); + Assert.Equal(request.PortionCount, created.PortionCount); + + var fetched = await _client.GetFromJsonAsync( + $"/api/leftovers/{created!.Id}"); + + Assert.NotNull(fetched); + Assert.Equal(created.Id, fetched!.Id); + Assert.Equal(request.Name, fetched.Name); + Assert.Equal(request.PortionCount, fetched.PortionCount); + } + + [Fact] + public async Task GetAllLeftovers_ReturnsSortedByExpiry() + { + var today = DateOnly.FromDateTime(DateTime.UtcNow); + + await CreateLeftoverAsync( + new CreateLeftoverRequest( + "Tacos", + today, + today.AddDays(3), + 2, + null, + DateTime.UtcNow)); + + await CreateLeftoverAsync( + new CreateLeftoverRequest( + "Soup", + today, + today.AddDays(1), + 4, + "Reheat gently", + DateTime.UtcNow)); + + var leftovers = await _client.GetFromJsonAsync>( + "/api/leftovers"); + + Assert.NotNull(leftovers); + Assert.Equal(2, leftovers!.Count); + Assert.Equal("Soup", leftovers[0].Name); + Assert.Equal("Tacos", leftovers[1].Name); + Assert.True(leftovers[0].ExpiresOn <= leftovers[1].ExpiresOn); + } + + [Fact] + public async Task GetLeftoverById_ReturnsNotFoundForMissing() + { + var response = await _client.GetAsync("/api/leftovers/9999"); + + Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); + } + + private Task CreateLeftoverAsync(CreateLeftoverRequest request) => + _client.PostAsJsonAsync("/api/leftovers", request); +} diff --git a/backend/Cauldron.Api.Tests/TestApplicationFactory.cs b/backend/Cauldron.Api.Tests/TestApplicationFactory.cs new file mode 100644 index 0000000..b7aebd4 --- /dev/null +++ b/backend/Cauldron.Api.Tests/TestApplicationFactory.cs @@ -0,0 +1,32 @@ +using Cauldron.Api.Data; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Mvc.Testing; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; + +namespace Cauldron.Api.Tests; + +public class TestApplicationFactory : WebApplicationFactory +{ + protected override void ConfigureWebHost(IWebHostBuilder builder) + { + builder.UseEnvironment("Development"); + + builder.ConfigureServices(services => + { + services.RemoveAll(typeof(CauldronDbContext)); + services.RemoveAll(typeof(DbContextOptions)); + services.RemoveAll(typeof(IDbContextFactory)); + + var connectionString = $"Data Source=cauldron-tests-{Guid.NewGuid()}.db"; + + services.AddDbContext(options => + options.UseSqlite(connectionString)); + + using var scope = services.BuildServiceProvider().CreateScope(); + var db = scope.ServiceProvider.GetRequiredService(); + db.Database.EnsureCreated(); + }); + } +} diff --git a/backend/Cauldron.Api.Tests/Usings.cs b/backend/Cauldron.Api.Tests/Usings.cs new file mode 100644 index 0000000..c802f44 --- /dev/null +++ b/backend/Cauldron.Api.Tests/Usings.cs @@ -0,0 +1 @@ +global using Xunit; diff --git a/backend/Cauldron.Api/Cauldron.Api.sln b/backend/Cauldron.Api/Cauldron.Api.sln index c5be56a..b8e5164 100644 --- a/backend/Cauldron.Api/Cauldron.Api.sln +++ b/backend/Cauldron.Api/Cauldron.Api.sln @@ -2,15 +2,44 @@ Microsoft Visual Studio Solution File, Format Version 12.00 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cauldron.Api", "Cauldron.Api.csproj", "{5B9D48AF-5D22-4CE8-B3E6-A53155145B55}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cauldron.Api.Tests", "..\Cauldron.Api.Tests\Cauldron.Api.Tests.csproj", "{01924E5B-0E5D-448C-B390-E5C5846DAD85}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {5B9D48AF-5D22-4CE8-B3E6-A53155145B55}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5B9D48AF-5D22-4CE8-B3E6-A53155145B55}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5B9D48AF-5D22-4CE8-B3E6-A53155145B55}.Debug|x64.ActiveCfg = Debug|Any CPU + {5B9D48AF-5D22-4CE8-B3E6-A53155145B55}.Debug|x64.Build.0 = Debug|Any CPU + {5B9D48AF-5D22-4CE8-B3E6-A53155145B55}.Debug|x86.ActiveCfg = Debug|Any CPU + {5B9D48AF-5D22-4CE8-B3E6-A53155145B55}.Debug|x86.Build.0 = Debug|Any CPU {5B9D48AF-5D22-4CE8-B3E6-A53155145B55}.Release|Any CPU.ActiveCfg = Release|Any CPU {5B9D48AF-5D22-4CE8-B3E6-A53155145B55}.Release|Any CPU.Build.0 = Release|Any CPU + {5B9D48AF-5D22-4CE8-B3E6-A53155145B55}.Release|x64.ActiveCfg = Release|Any CPU + {5B9D48AF-5D22-4CE8-B3E6-A53155145B55}.Release|x64.Build.0 = Release|Any CPU + {5B9D48AF-5D22-4CE8-B3E6-A53155145B55}.Release|x86.ActiveCfg = Release|Any CPU + {5B9D48AF-5D22-4CE8-B3E6-A53155145B55}.Release|x86.Build.0 = Release|Any CPU + {01924E5B-0E5D-448C-B390-E5C5846DAD85}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {01924E5B-0E5D-448C-B390-E5C5846DAD85}.Debug|Any CPU.Build.0 = Debug|Any CPU + {01924E5B-0E5D-448C-B390-E5C5846DAD85}.Debug|x64.ActiveCfg = Debug|Any CPU + {01924E5B-0E5D-448C-B390-E5C5846DAD85}.Debug|x64.Build.0 = Debug|Any CPU + {01924E5B-0E5D-448C-B390-E5C5846DAD85}.Debug|x86.ActiveCfg = Debug|Any CPU + {01924E5B-0E5D-448C-B390-E5C5846DAD85}.Debug|x86.Build.0 = Debug|Any CPU + {01924E5B-0E5D-448C-B390-E5C5846DAD85}.Release|Any CPU.ActiveCfg = Release|Any CPU + {01924E5B-0E5D-448C-B390-E5C5846DAD85}.Release|Any CPU.Build.0 = Release|Any CPU + {01924E5B-0E5D-448C-B390-E5C5846DAD85}.Release|x64.ActiveCfg = Release|Any CPU + {01924E5B-0E5D-448C-B390-E5C5846DAD85}.Release|x64.Build.0 = Release|Any CPU + {01924E5B-0E5D-448C-B390-E5C5846DAD85}.Release|x86.ActiveCfg = Release|Any CPU + {01924E5B-0E5D-448C-B390-E5C5846DAD85}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE EndGlobalSection EndGlobal diff --git a/backend/Cauldron.Api/Program.cs b/backend/Cauldron.Api/Program.cs index a68f184..905c031 100644 --- a/backend/Cauldron.Api/Program.cs +++ b/backend/Cauldron.Api/Program.cs @@ -31,3 +31,5 @@ app.MapLeftoverEndpoints(); app.Run(); + +public partial class Program; diff --git a/frontend/cauldron/e2e/vue.spec.ts b/frontend/cauldron/e2e/vue.spec.ts index 87c0605..9eb82ce 100644 --- a/frontend/cauldron/e2e/vue.spec.ts +++ b/frontend/cauldron/e2e/vue.spec.ts @@ -1,8 +1,84 @@ import { test, expect } from '@playwright/test' -// See here how to get started: -// https://playwright.dev/docs/intro -test('visits the app root url', async ({ page }) => { - await page.goto('/') - await expect(page.locator('h1')).toHaveText('You did it!') +const baseLeftovers = [ + { + id: 1, + name: 'Veggie soup', + madeOn: '2024-01-01', + expiresOn: '2024-01-04', + portionCount: 2, + notes: 'Light lunch', + createdAt: '2024-01-01T12:00:00Z', + }, +] + +test.describe('Leftovers view', () => { + test('shows leftovers returned by the API', async ({ page }) => { + await page.route('**/api/leftovers', async route => { + if (route.request().method() === 'GET') { + return route.fulfill({ + status: 200, + headers: { 'content-type': 'application/json' }, + body: JSON.stringify(baseLeftovers), + }) + } + + return route.fallback() + }) + + await page.goto('/leftovers') + + await expect(page.getByText('Leftovers')).toBeVisible() + await expect(page.getByText('Veggie soup')).toBeVisible() + await expect(page.getByText('No leftovers yet.')).toHaveCount(0) + }) + + test('creates a leftover and prepends it in the table', async ({ page }) => { + const leftovers = [...baseLeftovers] + + await page.route('**/api/leftovers', async route => { + const request = route.request() + + if (request.method() === 'GET') { + return route.fulfill({ + status: 200, + headers: { 'content-type': 'application/json' }, + body: JSON.stringify(leftovers), + }) + } + + if (request.method() === 'POST') { + const body = await request.postDataJSON() + const created = { + ...body, + id: leftovers.length + 1, + } + leftovers.unshift(created) + + return route.fulfill({ + status: 201, + headers: { 'content-type': 'application/json' }, + body: JSON.stringify(created), + }) + } + + return route.fallback() + }) + + await page.goto('/leftovers') + + await expect(page.getByText('Veggie soup')).toBeVisible() + + const expiresOn = new Date().toISOString().slice(0, 10) + + await page.getByLabel('Name').fill('Chili') + await page.getByLabel('Expires on').fill(expiresOn) + await page.getByLabel('Portions').fill('3') + await page.getByLabel('Notes').fill('Nice and spicy') + + await page.getByRole('button', { name: 'Add leftover' }).click() + + await expect(page.getByText('Chili')).toBeVisible() + await expect(page.getByText('Nice and spicy')).toBeVisible() + }) }) diff --git a/frontend/cauldron/src/__tests__/App.spec.ts b/frontend/cauldron/src/__tests__/App.spec.ts index 5b17801..31d54de 100644 --- a/frontend/cauldron/src/__tests__/App.spec.ts +++ b/frontend/cauldron/src/__tests__/App.spec.ts @@ -1,11 +1,19 @@ import { describe, it, expect } from 'vitest' - import { mount } from '@vue/test-utils' import App from '../App.vue' describe('App', () => { - it('mounts renders properly', () => { - const wrapper = mount(App) - expect(wrapper.text()).toContain('You did it!') + it('renders the router view placeholder', () => { + const wrapper = mount(App, { + global: { + stubs: { + RouterView: { + template: '
router
', + }, + }, + }, + }) + + expect(wrapper.text()).toContain('router') }) }) diff --git a/frontend/cauldron/src/__tests__/LeftoverForm.spec.ts b/frontend/cauldron/src/__tests__/LeftoverForm.spec.ts new file mode 100644 index 0000000..a51dc25 --- /dev/null +++ b/frontend/cauldron/src/__tests__/LeftoverForm.spec.ts @@ -0,0 +1,48 @@ +import { describe, it, expect } from 'vitest' +import { mount } from '@vue/test-utils' +import LeftoverForm from '../components/LeftoverForm.vue' +import type { CreateLeftoverRequest } from '../serverTypes/leftover' + +function today(): string { + return new Date().toISOString().slice(0, 10) +} + +describe('LeftoverForm', () => { + it('shows validation when name is missing', async () => { + const wrapper = mount(LeftoverForm) + + await wrapper.find('form').trigger('submit.prevent') + + expect(wrapper.text()).toContain('Name is required.') + expect(wrapper.emitted('submit')).toBeUndefined() + }) + + it('emits cleaned payload when form is valid', async () => { + const wrapper = mount(LeftoverForm) + + const nameInput = wrapper.find('#name') + const expiresOnInput = wrapper.find('#expiresOn') + const portionInput = wrapper.find('#portionCount') + const notesInput = wrapper.find('#notes') + + await nameInput.setValue(' Chili ') + await expiresOnInput.setValue(today()) + await portionInput.setValue('3') + await notesInput.setValue('Leftover dinner') + + await wrapper.find('form').trigger('submit.prevent') + + const payload = wrapper.emitted('submit')?.[0]?.[0] as + | CreateLeftoverRequest + | undefined + + expect(payload).toBeDefined() + expect(payload?.name).toBe('Chili') + expect(payload?.expiresOn).toBe(today()) + expect(Number(payload?.portionCount)).toBe(3) + expect(payload?.notes).toBe('Leftover dinner') + + expect((nameInput.element as HTMLInputElement).value).toBe('') + expect((expiresOnInput.element as HTMLInputElement).value).toBe('') + }) +}) diff --git a/frontend/cauldron/src/__tests__/leftover.service.spec.ts b/frontend/cauldron/src/__tests__/leftover.service.spec.ts new file mode 100644 index 0000000..09b356b --- /dev/null +++ b/frontend/cauldron/src/__tests__/leftover.service.spec.ts @@ -0,0 +1,37 @@ +import { describe, it, expect, vi, afterEach } from 'vitest' +import { getLeftoverById } from '../services/leftover' +import type { LeftoverResponse } from '../serverTypes/leftover' + +afterEach(() => { + vi.unstubAllGlobals() +}) + +describe('leftover service', () => { + it('fetches leftover by id', async () => { + const leftover: LeftoverResponse = { + id: '7', + name: 'Pasta', + madeOn: '2024-01-01', + expiresOn: '2024-01-03', + portionCount: 2, + notes: 'With pesto', + createdAt: '2024-01-01T12:00:00Z', + } + + const mockFetch = vi.fn().mockResolvedValue({ + ok: true, + json: () => Promise.resolve(leftover), + }) + + vi.stubGlobal('fetch', mockFetch) + + const result = await getLeftoverById(7) + + expect(mockFetch).toHaveBeenCalledWith('/api/leftovers/7', { + method: 'GET', + headers: { Accept: 'application/json' }, + }) + + expect(result).toEqual(leftover) + }) +}) diff --git a/frontend/cauldron/src/services/leftover.ts b/frontend/cauldron/src/services/leftover.ts index 1ffc36a..a523fe2 100644 --- a/frontend/cauldron/src/services/leftover.ts +++ b/frontend/cauldron/src/services/leftover.ts @@ -20,15 +20,15 @@ export async function getLeftovers(): Promise { return handleResponse(response) } -export async function getLeftoverById(id: number): Promise { - const response = await fetch('/api/leftovers', { +export async function getLeftoverById(id: number): Promise { + const response = await fetch(`/api/leftovers/${id}`, { method: 'GET', headers: { Accept: 'application/json', }, }) - return handleResponse(response) + return handleResponse(response) } export async function createLeftover(request: CreateLeftoverRequest): Promise { From 6e98d1eac6812c2187e931d2faecfc1ab9366f34 Mon Sep 17 00:00:00 2001 From: ShiosOS Date: Sun, 8 Mar 2026 04:42:43 -0400 Subject: [PATCH 2/5] Update CI --- .github/workflows/ci.yml | 85 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..db2eb03 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,85 @@ +name: CI + +on: + push: + branches: + - main + pull_request: + +jobs: + backend-tests: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Cache NuGet + uses: actions/cache@v4 + with: + path: ~/.nuget/packages + key: nuget-${{ runner.os }}-${{ hashFiles('**/*.csproj') }} + restore-keys: | + nuget-${{ runner.os }}- + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: 10.0.x + + - name: Restore and test + run: dotnet test backend/Cauldron.Api/Cauldron.Api.sln + + frontend-unit: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Bun + uses: oven-sh/setup-bun@v1 + + - name: Cache Bun + uses: actions/cache@v4 + with: + path: ~/.bun/install/cache + key: bun-${{ runner.os }}-${{ hashFiles('frontend/cauldron/bun.lock') }} + restore-keys: | + bun-${{ runner.os }}- + + - name: Install dependencies + working-directory: frontend/cauldron + run: bun install + + - name: Run unit tests + working-directory: frontend/cauldron + run: bun test:unit + + frontend-e2e: + runs-on: ubuntu-latest + needs: frontend-unit + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Bun + uses: oven-sh/setup-bun@v1 + + - name: Cache Bun + uses: actions/cache@v4 + with: + path: ~/.bun/install/cache + key: bun-${{ runner.os }}-${{ hashFiles('frontend/cauldron/bun.lock') }} + restore-keys: | + bun-${{ runner.os }}- + + - name: Install dependencies + working-directory: frontend/cauldron + run: bun install + + - name: Install Playwright browsers + working-directory: frontend/cauldron + run: npx playwright install --with-deps + + - name: Run e2e tests + working-directory: frontend/cauldron + run: bun test:e2e From 76ee811b1c00bf8b37ebf92f9672a762c0691aa6 Mon Sep 17 00:00:00 2001 From: ShiosOS Date: Sun, 8 Mar 2026 04:50:59 -0400 Subject: [PATCH 3/5] Reset db state in tests --- .../LeftoverEndpointsTests.cs | 27 +++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/backend/Cauldron.Api.Tests/LeftoverEndpointsTests.cs b/backend/Cauldron.Api.Tests/LeftoverEndpointsTests.cs index 046a0c5..4626fbd 100644 --- a/backend/Cauldron.Api.Tests/LeftoverEndpointsTests.cs +++ b/backend/Cauldron.Api.Tests/LeftoverEndpointsTests.cs @@ -1,12 +1,35 @@ using System.Net; using System.Net.Http.Json; using Cauldron.Api.Contracts.Leftovers; +using Cauldron.Api.Data; +using Microsoft.Extensions.DependencyInjection; namespace Cauldron.Api.Tests; -public class LeftoverEndpointsTests(TestApplicationFactory factory) : IClassFixture +public class LeftoverEndpointsTests : IClassFixture, IAsyncLifetime { - private readonly HttpClient _client = factory.CreateClient(); + private readonly HttpClient _client; + private readonly IServiceScope _scope; + private readonly CauldronDbContext _db; + + public LeftoverEndpointsTests(TestApplicationFactory factory) + { + _client = factory.CreateClient(); + _scope = factory.Services.CreateScope(); + _db = _scope.ServiceProvider.GetRequiredService(); + } + + public async Task InitializeAsync() + { + _db.Leftovers.RemoveRange(_db.Leftovers); + await _db.SaveChangesAsync(); + } + + public Task DisposeAsync() + { + _scope.Dispose(); + return Task.CompletedTask; + } [Fact] public async Task CreateLeftover_PersistsAndCanBeFetched() From aefdb87266803b869224a3304c2f6204892364fc Mon Sep 17 00:00:00 2001 From: ShiosOS Date: Sun, 8 Mar 2026 04:52:46 -0400 Subject: [PATCH 4/5] Only run on published prs --- .github/workflows/ci.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index db2eb03..c03a7cf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,6 +9,7 @@ on: jobs: backend-tests: runs-on: ubuntu-latest + if: github.event_name != 'pull_request' || github.event.pull_request.draft == false steps: - name: Checkout uses: actions/checkout@v4 @@ -31,6 +32,7 @@ jobs: frontend-unit: runs-on: ubuntu-latest + if: github.event_name != 'pull_request' || github.event.pull_request.draft == false steps: - name: Checkout uses: actions/checkout@v4 @@ -57,6 +59,7 @@ jobs: frontend-e2e: runs-on: ubuntu-latest needs: frontend-unit + if: github.event_name != 'pull_request' || github.event.pull_request.draft == false steps: - name: Checkout uses: actions/checkout@v4 From 27937bd10b4a63eea009ff73a5bddb26b04b4ba4 Mon Sep 17 00:00:00 2001 From: ShiosOS Date: Sun, 8 Mar 2026 05:02:13 -0400 Subject: [PATCH 5/5] Fix e2e tests --- frontend/cauldron/playwright.config.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/frontend/cauldron/playwright.config.ts b/frontend/cauldron/playwright.config.ts index 5ece956..449bed3 100644 --- a/frontend/cauldron/playwright.config.ts +++ b/frontend/cauldron/playwright.config.ts @@ -99,11 +99,11 @@ export default defineConfig({ /* Run your local dev server before starting the tests */ webServer: { /** - * Use the dev server by default for faster feedback loop. - * Use the preview server on CI for more realistic testing. - * Playwright will re-use the local server if there is already a dev-server running. + * Use dev server locally; on CI build then run preview so assets are built. */ - command: process.env.CI ? 'npm run preview' : 'npm run dev', + command: process.env.CI + ? 'bun run build && bun run preview -- --host 0.0.0.0 --port 4173' + : 'bun dev -- --host 0.0.0.0 --port 5173', port: process.env.CI ? 4173 : 5173, reuseExistingServer: !process.env.CI, },