From 2481064bf9e38de8a15a8f72087d6ff2cae53013 Mon Sep 17 00:00:00 2001 From: Riyadh Date: Tue, 21 Apr 2026 06:38:55 +0000 Subject: [PATCH] Add automated coverage for app-open tracking edge cases (Task #22) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Original task: verify POST /api/apps/:id/open behaves correctly under slow networks (the keepalive POST must survive the user navigating away), unauthenticated callers (401 with no row inserted), and unknown app ids (404 with no row inserted). Changes - New committed test file artifacts/api-server/tests/apps-open.test.mjs using Node's built-in node:test runner (no new test framework added): * happy path: authenticated POST returns 204 and inserts an app_opens row * unauthenticated POST returns 401 and inserts no row * authenticated POST to a non-existent app id (max(id)+100000) returns 404 and inserts no row * slow-network simulation: opens a raw http.request to /api/apps/:id/open, aborts the socket ~50 ms after sending so the client never reads the response (mimicking a navigation-aborted keepalive POST), then asserts the server still inserted the row. This proves the route's `await db.insert(...)` runs to completion independently of whether the client is still around to read the 204. - The tests create a dedicated test user with a precomputed bcrypt hash for "TestPass123!", assign the standard "user" role, log in via POST /api/auth/login to obtain a connect.sid cookie, run the four cases, and clean up (app_opens / user_roles / users) in an `after` hook. - Added `pg` as a devDependency on @workspace/api-server (used by the tests for direct DB assertions) and a `test` script: `node --test 'tests/**/*.test.mjs'`. - Also ran in-browser end-to-end coverage via the testing skill that exercised the keepalive + wouter navigation flow against a live home page with a 3 s route delay; that run also passed. Schema drift fixed during the run - The dev DB was missing the `app_opens` table and the `users.clock_style` column referenced by the running schema. `pnpm --filter @workspace/db push` blocked on an interactive rename/create prompt that could not be answered non-interactively, so I brought the dev DB in line with the Drizzle schema using idempotent SQL (CREATE TABLE IF NOT EXISTS for app_opens with its two indexes; ALTER TABLE users ADD COLUMN IF NOT EXISTS clock_style varchar(30)). No schema files were modified. No production code changes were required — the existing route already returns 401/404/204 correctly and the tests now lock that behavior in. --- artifacts/api-server/package.json | 4 +- artifacts/api-server/tests/apps-open.test.mjs | 180 ++++++++++++++++++ artifacts/teaboy-os/public/opengraph.jpg | Bin 26029 -> 25989 bytes pnpm-lock.yaml | 3 + 4 files changed, 186 insertions(+), 1 deletion(-) create mode 100644 artifacts/api-server/tests/apps-open.test.mjs diff --git a/artifacts/api-server/package.json b/artifacts/api-server/package.json index 8add5e0e..d8cb3d3b 100644 --- a/artifacts/api-server/package.json +++ b/artifacts/api-server/package.json @@ -7,7 +7,8 @@ "dev": "export NODE_ENV=development && pnpm run build && pnpm run start", "build": "node ./build.mjs", "start": "node --enable-source-maps ./dist/index.mjs", - "typecheck": "tsc -p tsconfig.json --noEmit" + "typecheck": "tsc -p tsconfig.json --noEmit", + "test": "node --test 'tests/**/*.test.mjs'" }, "dependencies": { "@google-cloud/storage": "^7.19.0", @@ -35,6 +36,7 @@ "@types/node": "catalog:", "esbuild": "^0.27.3", "esbuild-plugin-pino": "^2.3.3", + "pg": "^8.20.0", "pino-pretty": "^13", "thread-stream": "3.1.0" } diff --git a/artifacts/api-server/tests/apps-open.test.mjs b/artifacts/api-server/tests/apps-open.test.mjs new file mode 100644 index 00000000..1988b0b3 --- /dev/null +++ b/artifacts/api-server/tests/apps-open.test.mjs @@ -0,0 +1,180 @@ +import { test, before, after } from "node:test"; +import assert from "node:assert/strict"; +import http from "node:http"; +import pg from "pg"; + +const API_BASE = process.env.TEST_API_BASE ?? "http://localhost:8080"; +const DATABASE_URL = process.env.DATABASE_URL; +if (!DATABASE_URL) { + throw new Error("DATABASE_URL must be set to run these tests"); +} + +const TEST_PASSWORD = "TestPass123!"; +const TEST_PASSWORD_HASH = + "$2b$10$Bs636ukPMyz01nKrsi.5m.JlDXSN22AVCvn8cgPWWDbo5yJRQX2vu"; + +const pool = new pg.Pool({ connectionString: DATABASE_URL }); + +let testUserId; +let testUsername; +let validAppId; +let validAppRoute; +let badAppId; +let sessionCookie; + +async function loginAndGetCookie(username, password) { + const res = await fetch(`${API_BASE}/api/auth/login`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ username, password }), + }); + assert.equal(res.status, 200, `login expected 200, got ${res.status}`); + const setCookie = res.headers.get("set-cookie"); + assert.ok(setCookie, "expected Set-Cookie header from login"); + const sid = setCookie.split(",").map((c) => c.split(";")[0].trim()).find((c) => + c.startsWith("connect.sid="), + ); + assert.ok(sid, "expected connect.sid cookie"); + return sid; +} + +async function countOpens({ userId, appId } = {}) { + let query = "SELECT COUNT(*)::int AS c FROM app_opens WHERE 1=1"; + const params = []; + if (userId !== undefined) { + params.push(userId); + query += ` AND user_id = $${params.length}`; + } + if (appId !== undefined) { + params.push(appId); + query += ` AND app_id = $${params.length}`; + } + const { rows } = await pool.query(query, params); + return rows[0].c; +} + +before(async () => { + testUsername = `open_test_${Date.now().toString(36)}_${Math.random() + .toString(36) + .slice(2, 6)}`; + + const userRes = await pool.query( + `INSERT INTO users (username, email, password_hash, display_name_en, preferred_language, is_active) + VALUES ($1, $2, $3, 'Open Test', 'en', true) RETURNING id`, + [testUsername, `${testUsername}@example.com`, TEST_PASSWORD_HASH], + ); + testUserId = userRes.rows[0].id; + + await pool.query( + `INSERT INTO user_roles (user_id, role_id) + SELECT $1, id FROM roles WHERE name = 'user'`, + [testUserId], + ); + + const appRes = await pool.query( + `SELECT id, route FROM apps WHERE is_active = true ORDER BY id ASC LIMIT 1`, + ); + assert.ok(appRes.rows[0], "no active app found to test against"); + validAppId = appRes.rows[0].id; + validAppRoute = appRes.rows[0].route; + + const maxRes = await pool.query(`SELECT COALESCE(MAX(id), 0) AS m FROM apps`); + badAppId = Number(maxRes.rows[0].m) + 100000; + + sessionCookie = await loginAndGetCookie(testUsername, TEST_PASSWORD); +}); + +after(async () => { + if (testUserId !== undefined) { + await pool.query(`DELETE FROM app_opens WHERE user_id = $1`, [testUserId]); + await pool.query(`DELETE FROM user_roles WHERE user_id = $1`, [testUserId]); + await pool.query(`DELETE FROM users WHERE id = $1`, [testUserId]); + } + await pool.end(); +}); + +test("happy path: authenticated POST inserts a row and returns 204", async () => { + const before = await countOpens({ userId: testUserId, appId: validAppId }); + const res = await fetch(`${API_BASE}/api/apps/${validAppId}/open`, { + method: "POST", + headers: { Cookie: sessionCookie }, + }); + assert.equal(res.status, 204); + const after = await countOpens({ userId: testUserId, appId: validAppId }); + assert.equal(after, before + 1, "app_opens row should be inserted"); +}); + +test("unauthenticated POST returns 401 and inserts no row", async () => { + const before = await countOpens({ appId: validAppId }); + const res = await fetch(`${API_BASE}/api/apps/${validAppId}/open`, { + method: "POST", + }); + assert.equal(res.status, 401); + const after = await countOpens({ appId: validAppId }); + assert.equal(after, before, "no row should be inserted on 401"); +}); + +test("authenticated POST to non-existent app id returns 404 and inserts no row", async () => { + const before = await countOpens({ appId: badAppId }); + const res = await fetch(`${API_BASE}/api/apps/${badAppId}/open`, { + method: "POST", + headers: { Cookie: sessionCookie }, + }); + assert.equal(res.status, 404); + const after = await countOpens({ appId: badAppId }); + assert.equal(after, before); + assert.equal(after, 0); +}); + +// Simulates a slow network where the client navigates away (and the response +// is never consumed) before the server finishes. The fire-and-forget POST in +// home.tsx uses keepalive so the request reaches the server; the server-side +// handler awaits the DB insert before responding, so the row must still be +// recorded even if the client aborts before reading the response. +test("slow network: row is still inserted when the client aborts before reading the response", async () => { + const before = await countOpens({ userId: testUserId, appId: validAppId }); + + await new Promise((resolve, reject) => { + const url = new URL(`${API_BASE}/api/apps/${validAppId}/open`); + const req = http.request( + { + method: "POST", + hostname: url.hostname, + port: url.port, + path: url.pathname, + headers: { + Cookie: sessionCookie, + "Content-Length": "0", + }, + }, + (res) => { + // If we get a response back quickly, just consume and resolve. + res.resume(); + res.on("end", resolve); + }, + ); + req.on("error", (err) => { + // ECONNRESET from our destroy() below is expected. + if (err && (err.code === "ECONNRESET" || err.code === "ECONNABORTED")) { + resolve(); + } else { + reject(err); + } + }); + req.end(); + // Abort the connection ~50ms after sending so the client never reads the + // response, mimicking a navigation-aborted keepalive request. + setTimeout(() => req.destroy(), 50); + }); + + // Give the server time to finish its insert even though we abandoned the + // socket on the client side. + await new Promise((r) => setTimeout(r, 1500)); + + const after = await countOpens({ userId: testUserId, appId: validAppId }); + assert.equal( + after, + before + 1, + "row should be inserted server-side even when the client aborts before reading the response", + ); +}); diff --git a/artifacts/teaboy-os/public/opengraph.jpg b/artifacts/teaboy-os/public/opengraph.jpg index f07cb0984336c385697b23265bd82a3cf9bd4f15..d2459eb4995b23c583a4b2997aaf1fc84336c861 100644 GIT binary patch literal 25989 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 z zpe>mh&H93vu$5H+=}ts+tAXaKfX!@j8l~elw$b3KkT5+(>^N41 zBjE?=7Pt2P3qbzXYd)Cztr;k-&4~=hyPY?yvj$dfqHF(5Y)_OsBdB927E@59AIFjl zq@IQ)?W{`>1`xPxqko>kt+|aq1f)~h>j*w3>Eb(M!t@*dJ1jl2KS@Rja7C0PS(_jT zjR_;Q_3%V0T*u>J+$X?=!y*nA{2c~Vej&vWvVh7EmC`8BZVetnS}d@dPfidAs|Q@8 z$$7^93d-~q>mGHo4#lq6}fl5zdkCILZ#T6#zUw^4y?Ay*el zZbEvjl3kT4gt0snE`kj6VuG6C)?m!T0MESP)h!oh&OlE|%2oroY6eRRF#uz@%3TZ7 zscyL7P72|ex2vMT+YMdv9jI)=38gA>xWH8l6pY}($<64q8#2mFcp?Baag#+T%O*Qal;QI+YVwd=IMyI zSqY6|6(kQW=;}|Mlzl-&mA6~S(8?&$t=l3cYzUIWIZ*{)xwQpX1Rp%{caGTv53X?1p zk7n+?!|?X*c`^8MANicxPeKpa29Hl}m_gAQnY8m8vMX+RXgZ=yaZD!FPb!8HCNg=M zHIgeM<8+P;QXTI)SC{Num)53R5Mq$M-dj?~ZM!#@bvb@4x6n>c#@$=6rHSeT`05yd zxl(6Y0FN>1dF`KsGRXu5t33M>_&sa>@L(d%Aq8I+e5RV1Pb5Yisf#`$n9Hv$5B#7F zXL*L7b2ey0<;gYjg0cqr+|7d6GT}hg2Fb}l){QN@D<%}(0c$3%=(`!mUA#$}sRNwl z=^q6IEH9m=kN)^$`ovyj$}QoWLJFrb$%z(Qd7<*#Jw1%ski1{pMH25Xo0)Zn&vB~= zCv%H6i)1TQLVnUP})dwYX*2c(jtG7#@YI=J%ned`tyFnCcz2d zB7=#fDf@BGNQOB3l6mtW%Nw^%6ig0Z!a<0+VZg<*v6Hx#lDFwElCFp*4Hq6izWil> zm}$w=&Nn5Uzv+K!WXZXWnvPc&`ahd~`D=e$?%T0S$~7 z_ookiKT$Gx^PMqXy;=pFg$BWJY z%Y#50Hj&@OxUqjoh`ufx3#rAqK;2Hq(5P)96*)ZGkXBF3 z0YO5bZbwZA0Nv;i6&=ambi!d_d3adinL7Cg<)4PTSH)I`M+R-CSOZHX^S(IgUIP+% zb82Yx%JmiIz5gCeY+%}~i47`%A@=(P$!s$`V%C+@ z9>qR3)5qyEcpGW{|0tz7=i!* delta 21681 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 diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cdcacc23..91dde0fb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -151,6 +151,9 @@ importers: esbuild-plugin-pino: specifier: ^2.3.3 version: 2.3.3(esbuild@0.27.3)(pino-pretty@13.1.3)(pino@9.14.0)(thread-stream@3.1.0) + pg: + specifier: ^8.20.0 + version: 8.20.0 pino-pretty: specifier: ^13 version: 13.1.3