From 208affad91c6daa81ba94b2a4419d6bb7ee13683 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
<41898282+github-actions[bot]@users.noreply.github.com>
Date: Wed, 29 Jul 2026 22:03:44 -0300
Subject: [PATCH 1/2] refactor(test): extract generateInvite helper
---
tests/unit/screens/SettingsScreen.test.tsx | 39 ++++++++--------------
1 file changed, 14 insertions(+), 25 deletions(-)
diff --git a/tests/unit/screens/SettingsScreen.test.tsx b/tests/unit/screens/SettingsScreen.test.tsx
index bc41ebcb..d28e0251 100644
--- a/tests/unit/screens/SettingsScreen.test.tsx
+++ b/tests/unit/screens/SettingsScreen.test.tsx
@@ -1,3 +1,4 @@
+import type { UserEvent } from '@testing-library/user-event';
import { server } from '@tests/mocks/node';
import { fireEvent, render, screen, userEvent } from '@tests/mocks/test-utils';
import { HttpResponse, http } from 'msw';
@@ -26,6 +27,15 @@ vi.mock('@/lib/local-storage-utils', () => ({
clearAllStorage: vi.fn(() => Promise.resolve()),
}));
+async function generateInvite(user: UserEvent) {
+ await user.type(
+ screen.getByLabelText('Remote Archive URL'),
+ 'https://archive.example.com',
+ );
+ await user.type(screen.getByLabelText('Bearer Token'), 'my-secret-token');
+ await user.click(screen.getByRole('button', { name: 'Generate Invite' }));
+}
+
beforeEach(async () => {
await resetDb();
useAuthStore.setState({
@@ -82,12 +92,7 @@ describe('SettingsScreen', () => {
const user = userEvent.setup();
render();
- await user.type(
- screen.getByLabelText('Remote Archive URL'),
- 'https://archive.example.com',
- );
- await user.type(screen.getByLabelText('Bearer Token'), 'my-secret-token');
- await user.click(screen.getByRole('button', { name: 'Generate Invite' }));
+ await generateInvite(user);
// Results header should appear
expect(await screen.findByText('Results')).toBeInTheDocument();
@@ -113,12 +118,7 @@ describe('SettingsScreen', () => {
const user = userEvent.setup();
render();
- await user.type(
- screen.getByLabelText('Remote Archive URL'),
- 'https://archive.example.com',
- );
- await user.type(screen.getByLabelText('Bearer Token'), 'my-secret-token');
- await user.click(screen.getByRole('button', { name: 'Generate Invite' }));
+ await generateInvite(user);
expect(await screen.findByText('Expires in 24 hours.')).toBeInTheDocument();
});
@@ -141,12 +141,7 @@ describe('SettingsScreen', () => {
const user = userEvent.setup();
render();
- await user.type(
- screen.getByLabelText('Remote Archive URL'),
- 'https://archive.example.com',
- );
- await user.type(screen.getByLabelText('Bearer Token'), 'my-secret-token');
- await user.click(screen.getByRole('button', { name: 'Generate Invite' }));
+ await generateInvite(user);
expect(
await screen.findByText(
@@ -163,13 +158,7 @@ describe('SettingsScreen', () => {
const user = userEvent.setup();
render();
- // Fill form and generate
- await user.type(
- screen.getByLabelText('Remote Archive URL'),
- 'https://archive.example.com',
- );
- await user.type(screen.getByLabelText('Bearer Token'), 'my-secret-token');
- await user.click(screen.getByRole('button', { name: 'Generate Invite' }));
+ await generateInvite(user);
// Wait for results to render
await screen.findByText('Results');
From f05dab8daeed7c621370523f329a9876b63385f8 Mon Sep 17 00:00:00 2001
From: Terrastories
Date: Thu, 30 Jul 2026 22:35:46 -0300
Subject: [PATCH 2/2] ci(smoke): poll /api/info until Functions are live before
asserting 400
The preview smoke test failed with "Expected 400 ... got 404" because it
probed /api/info once, ~8s after "Deployment complete". Cloudflare Pages
Functions take a few seconds to propagate; until they are live, /api/*
falls through to the static 404 handler. A live probe minutes later returns
the correct 400.
Replace the single-shot probe with a poll that retries until the function
answers 400, while still asserting the final status is exactly 400 (no
suppression). Applied to the identical preview/staging/prod blocks; bumped
those smoke jobs to a 5m timeout to absorb the worst-case poll.
Co-Authored-By: Claude
---
.github/workflows/ci.yml | 46 +++++++++++++++++++++++++++++++++++-----
1 file changed, 41 insertions(+), 5 deletions(-)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index ec7a94dd..347caebc 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -615,7 +615,7 @@ jobs:
needs: preview
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
- timeout-minutes: 3
+ timeout-minutes: 5
steps:
- name: Smoke test — app reachability
run: |
@@ -627,7 +627,19 @@ jobs:
- name: Smoke test — API proxy rejects missing target
run: |
- STATUS=$(curl -s -o /dev/null -w "%{http_code}" "${{ needs.preview.outputs.preview-url }}/api/info")
+ # Pages Functions propagate a few seconds after "Deployment complete";
+ # until they are live, /api/* falls through to the static 404 handler.
+ # Poll until the function answers (400) instead of failing on the first
+ # request, but still assert the final status is exactly 400.
+ STATUS=""
+ for i in $(seq 1 6); do
+ STATUS=$(curl -s -o /dev/null -w "%{http_code}" "${{ needs.preview.outputs.preview-url }}/api/info")
+ if [ "$STATUS" = "400" ]; then
+ break
+ fi
+ echo "Attempt $i: expected 400, got $STATUS (Functions may still be propagating); retrying in 10s..."
+ sleep 10
+ done
if [ "$STATUS" != "400" ]; then
echo "Expected 400 for /api/info without x-target-url, got $STATUS"
exit 1
@@ -827,7 +839,19 @@ jobs:
- name: Smoke test — API proxy rejects missing target
run: |
- STATUS=$(curl -s -o /dev/null -w "%{http_code}" "${{ vars.STAGING_URL || needs.staging.outputs.deployment-url }}/api/info")
+ # Pages Functions propagate a few seconds after "Deployment complete";
+ # until they are live, /api/* falls through to the static 404 handler.
+ # Poll until the function answers (400) instead of failing on the first
+ # request, but still assert the final status is exactly 400.
+ STATUS=""
+ for i in $(seq 1 6); do
+ STATUS=$(curl -s -o /dev/null -w "%{http_code}" "${{ vars.STAGING_URL || needs.staging.outputs.deployment-url }}/api/info")
+ if [ "$STATUS" = "400" ]; then
+ break
+ fi
+ echo "Attempt $i: expected 400, got $STATUS (Functions may still be propagating); retrying in 15s..."
+ sleep 15
+ done
if [ "$STATUS" != "400" ]; then
echo "Expected 400 for /api/info without x-target-url, got $STATUS"
exit 1
@@ -911,7 +935,7 @@ jobs:
needs: deploy
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
runs-on: ubuntu-latest
- timeout-minutes: 3
+ timeout-minutes: 5
steps:
- name: Smoke test — app reachability
run: |
@@ -923,7 +947,19 @@ jobs:
- name: Smoke test — API proxy rejects missing target
run: |
- STATUS=$(curl -s -o /dev/null -w "%{http_code}" "https://app.comapeo.cloud/api/info")
+ # Pages Functions propagate a few seconds after "Deployment complete";
+ # until they are live, /api/* falls through to the static 404 handler.
+ # Poll until the function answers (400) instead of failing on the first
+ # request, but still assert the final status is exactly 400.
+ STATUS=""
+ for i in $(seq 1 6); do
+ STATUS=$(curl -s -o /dev/null -w "%{http_code}" "https://app.comapeo.cloud/api/info")
+ if [ "$STATUS" = "400" ]; then
+ break
+ fi
+ echo "Attempt $i: expected 400, got $STATUS (Functions may still be propagating); retrying in 10s..."
+ sleep 10
+ done
if [ "$STATUS" != "400" ]; then
echo "Expected 400 for /api/info without x-target-url, got $STATUS"
exit 1