Compare commits

...

2 Commits

Author SHA1 Message Date
peptiderepo
da4662ae88 fix(ci): sync package-lock.json with package.json (unblock smoke npm ci)
Playwright packages were pinned at 1.59.1 in the lock but package.json
specifies ^1.60.0; typescript 6.0.3 was listed in package.json dependencies
but entirely absent from the lock. Both caused `npm ci` to abort, blocking
the org-wide smoke gate on every deploy pipeline.

Regenerated with `npm install --package-lock-only`:
- @playwright/test: 1.59.1 → 1.60.0
- playwright:       1.59.1 → 1.60.0
- playwright-core:  1.59.1 → 1.60.0
- typescript:       (missing) → 6.0.3

No source files, no version bumps, no behavior changes.

Agent-Session: e2e-lockfile-sync
2026-06-13 06:18:03 +00:00
peptiderepo
65c5de61cb test: dossier edit+rerun smoke (M3, skip-if-absent) — v1.4.0 (#15)
QA: APPROVE (companion verdict in qa-reviews/prautoblogger/2026-06-12-6ed639d.md check 10). Skip-if-absent per M3 binding.

Agent-Session: cto-e2e-merge-20260612
2026-06-12 22:04:20 +07:00
4 changed files with 184 additions and 16 deletions

View File

@@ -2,6 +2,19 @@
All notable changes to the peptide-e2e smoke suite will be documented here.
## [1.4.0] - 2026-06-12
### Added
- **Dossier edit + re-run smoke (M3, skip-if-absent)** (`05-dossier-edit.spec.ts`).
Opens a discovered post's dossier and exercises the v0.20.0 edit surface READ-ONLY:
opens/closes the first edit panel (asserts textareas, Save/Re-run buttons, the
fork-preserved + queued-execution copy), asserts every disabled edit affordance
carries a visible reason, and checks the M3 sidebar cards (Run Spend, Models &
Prompts). NEVER clicks Save or any Re-run button (those fork inputs / queue paid
LLM jobs). SKIPS with a loud annotation when `.prab-stage-rerun-footer` is absent
(plugin v0.20.0 not yet deployed) so this PR can merge before prautoblogger PR #161
per the M3 merge-order binding. 25 tests total (was 24), delta = 1.
## [1.3.0] - 2026-06-12
### Fixed

44
package-lock.json generated
View File

@@ -1,25 +1,28 @@
{
"name": "peptide-e2e",
"version": "1.0.0",
"version": "1.4.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "peptide-e2e",
"version": "1.0.0",
"version": "1.4.0",
"dependencies": {
"typescript": "^6.0.3"
},
"devDependencies": {
"@playwright/test": "^1.43.0",
"@playwright/test": "^1.60.0",
"dotenv": "^16.4.5"
}
},
"node_modules/@playwright/test": {
"version": "1.59.1",
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.59.1.tgz",
"integrity": "sha512-PG6q63nQg5c9rIi4/Z5lR5IVF7yU5MqmKaPOe0HSc0O2cX1fPi96sUQu5j7eo4gKCkB2AnNGoWt7y4/Xx3Kcqg==",
"version": "1.60.0",
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.60.0.tgz",
"integrity": "sha512-O71yZIbAh/PxDMNGns37GHBIfrVkEVyn+AXyIa5dOTfb4/xNvRWV+Vv/NMbNCtODB/pO7vLlF2OTmMVLhmr7Ag==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"playwright": "1.59.1"
"playwright": "1.60.0"
},
"bin": {
"playwright": "cli.js"
@@ -57,13 +60,13 @@
}
},
"node_modules/playwright": {
"version": "1.59.1",
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.59.1.tgz",
"integrity": "sha512-C8oWjPR3F81yljW9o5OxcWzfh6avkVwDD2VYdwIGqTkl+OGFISgypqzfu7dOe4QNLL2aqcWBmI3PMtLIK233lw==",
"version": "1.60.0",
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.60.0.tgz",
"integrity": "sha512-hheHdokM8cdqCb0lcE3s+zT4t4W+vvjpGxsZlDnikarzx8tSzMebh3UiFtgqwFwnTnjYQcsyMF8ei2mCO/tpeA==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"playwright-core": "1.59.1"
"playwright-core": "1.60.0"
},
"bin": {
"playwright": "cli.js"
@@ -76,9 +79,9 @@
}
},
"node_modules/playwright-core": {
"version": "1.59.1",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.59.1.tgz",
"integrity": "sha512-HBV/RJg81z5BiiZ9yPzIiClYV/QMsDCKUyogwH9p3MCP6IYjUFu/MActgYAvK0oWyV9NlwM3GLBjADyWgydVyg==",
"version": "1.60.0",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.60.0.tgz",
"integrity": "sha512-9bW6zvX/m0lEbgTKJ6YppOKx8H3VOPBMOCFh2irXFOT4BbHgrx5hPjwJYLT40Lu+4qtD36qKc/Hn56StUW57IA==",
"dev": true,
"license": "Apache-2.0",
"bin": {
@@ -87,6 +90,19 @@
"engines": {
"node": ">=18"
}
},
"node_modules/typescript": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz",
"integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==",
"license": "Apache-2.0",
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
"node": ">=14.17"
}
}
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "peptide-e2e",
"version": "1.3.0",
"version": "1.4.0",
"description": "Playwright smoke tests for peptiderepo.com (staging + production)",
"private": true,
"scripts": {
@@ -11,7 +11,10 @@
"report": "playwright show-report"
},
"devDependencies": {
"@playwright/test": "^1.43.0",
"@playwright/test": "^1.60.0",
"dotenv": "^16.4.5"
},
"dependencies": {
"typescript": "^6.0.3"
}
}

View File

@@ -0,0 +1,136 @@
/**
* 05-dossier-edit.spec.ts
*
* What: Smoke for the PRAutoBlogger dossier EDIT + RE-RUN surface
* (plugin v0.20.0, Phase 2 admin M3). Read-only: opens/closes the
* edit panel and asserts structure — it NEVER clicks Save or any
* Re-run button (those fork inputs / queue paid LLM jobs).
* Who triggers it: Playwright chromium project (post-auth setup).
* Dependencies: wp-admin authenticated session (from global.setup.ts).
*
* SKIP-IF-ABSENT (M3 binding): this spec targets a surface that may not
* be deployed yet. When the M3 markup (.prab-stage-rerun-footer) is
* absent from the dossier, the test SKIPS with a loud annotation so this
* PR can merge before the plugin PR ships. Once v0.20.0 is live, the
* skip path goes dead and the assertions gate as usual.
*
* Selectors sourced from prautoblogger v0.20.0:
* templates/admin/dossier-stage-section.php (.prab-stage-rerun-footer,
* .prab-edit-toggle, .prab-edit-unavailable, .prab-rerun-from)
* templates/admin/dossier-edit-panel.php (.prab-edit-panel,
* .prab-edit-textarea, .prab-edit-save, .prab-edit-rerun)
* templates/admin/dossier-sidebar-cards.php (.prab-run-spend,
* .prab-models-card)
*
* @see prautoblogger PR #161 (v0.20.0) — the surface under test.
*/
import { test, expect } from '@playwright/test';
const ADMIN = '/wp-admin';
const CANDIDATE_POST_IDS = [925, 930]; // canonical staging posts
test.describe('WP Admin — PRAutoBlogger dossier edit + re-run (M3)', () => {
test('edit affordances render structurally (no mutations)', async ({ page, request }) => {
// ── Post discovery (same defensive strategy as the dossier smoke) ──
let targetPostId: number | null = null;
for (const pid of CANDIDATE_POST_IDS) {
const apiRes = await request.get(`/wp-json/wp/v2/posts/${pid}`);
if (apiRes.ok()) {
targetPostId = pid;
break;
}
}
if (targetPostId === null) {
const listRes = await request.get('/wp-json/wp/v2/posts?per_page=5&orderby=date&order=desc');
if (listRes.ok()) {
const posts: Array<{ id: number }> = await listRes.json();
if (posts.length > 0) {
targetPostId = posts[0].id;
}
}
}
if (targetPostId === null) {
test.info().annotations.push({
type: 'warning',
description:
'[dossier-edit smoke] No post found on this environment — ' +
'cannot exercise the edit surface. Skipping.',
});
test.skip();
return;
}
const res = await page.goto(`${ADMIN}/admin.php?page=prautoblogger-dossier&post_id=${targetPostId}`);
expect(res?.status()).toBe(200);
await expect(page.locator('#wpbody')).toBeVisible();
const body = await page.textContent('body');
expect(body).not.toContain('Fatal error');
expect(body).not.toContain('Invalid plugin page');
// ── SKIP-IF-ABSENT gate: M3 markup not deployed yet ────────────────
const footers = page.locator('.prab-stage-rerun-footer');
const footerCount = await footers.count();
if (footerCount === 0) {
test.info().annotations.push({
type: 'warning',
description:
'[dossier-edit smoke] .prab-stage-rerun-footer absent — the M3 ' +
'edit+rerun surface (plugin v0.20.0) is not deployed on this ' +
'environment, or this post has no stage sections. Skipping per ' +
'the merge-early binding.',
});
test.skip();
return;
}
console.log(`[dossier-edit smoke] Found ${footerCount} stage rerun footers on post id=${targetPostId}`);
// ── Disabled affordances must explain themselves ───────────────────
const unavailable = page.locator('.prab-edit-unavailable');
const unavailableCount = await unavailable.count();
for (let i = 0; i < unavailableCount; i++) {
const reason = (await unavailable.nth(i).textContent())?.trim() ?? '';
expect(reason.length, 'disabled edit affordances must carry a visible reason').toBeGreaterThan(10);
}
// ── Edit panel open/close (read-only — NEVER click save/rerun) ─────
const toggles = page.locator('.prab-edit-toggle');
const toggleCount = await toggles.count();
if (toggleCount === 0) {
test.info().annotations.push({
type: 'info',
description:
'[dossier-edit smoke] No editable stage on this post (no recorded ' +
'request_json yet, or post is published/frozen). Disabled-state ' +
'reasons were asserted; panel interaction not exercisable.',
});
return;
}
const firstToggle = toggles.first();
const panelId = await firstToggle.getAttribute('aria-controls');
expect(panelId).toBeTruthy();
const panel = page.locator(`#${panelId}`);
await firstToggle.click();
await expect(panel).toBeVisible();
await expect(firstToggle).toHaveAttribute('aria-expanded', 'true');
// Panel structure: textareas + save + rerun buttons + fork/queue copy.
expect(await panel.locator('.prab-edit-textarea').count()).toBeGreaterThan(0);
await expect(panel.locator('.prab-edit-save')).toBeVisible();
await expect(panel.locator('.prab-edit-rerun')).toBeVisible();
const copy = (await panel.textContent()) ?? '';
expect(copy).toContain('original is preserved'); // fork copy (guardrail 1)
expect(copy.toLowerCase()).toContain('queued'); // chained-cron copy
// Close it again — leave the page exactly as found.
await firstToggle.click();
await expect(panel).toBeHidden();
// ── M3 sidebar cards present when run data exists ──────────────────
await expect(page.locator('.prab-run-spend')).toBeVisible();
await expect(page.locator('.prab-models-card')).toBeVisible();
});
});