config loads without Node's MODULE_TYPELESS_PACKAGE_JSON warning in a CommonJS project; capture sign-in docs use captureAuth and check notes a local capture that signs in with reviewDemoAccount (the App Review account)
This commit is contained in:
parent
2fdd96e68c
commit
8c1a01d856
5 changed files with 38 additions and 5 deletions
|
|
@ -2,6 +2,11 @@
|
|||
|
||||
## Unreleased
|
||||
|
||||
- **No more "Reparsing as ES module" warning** for a `.ts` config in a CommonJS project (Node's
|
||||
MODULE_TYPELESS_PACKAGE_JSON); the app does not need `"type": "module"`.
|
||||
- **Capture sign-in keeps App Review's account apart:** the docs use `captureAuth` for a local demo sign-in, and
|
||||
`check` notes a capture against localhost that uses `reviewDemoAccount` (the account `apple review-details` sends).
|
||||
|
||||
## 0.8.17 · 2026-10-20
|
||||
|
||||
- `shots capture --source web` can sign in first: `shots.capture.auth` is a sign-in request (run once per browser
|
||||
|
|
|
|||
|
|
@ -152,6 +152,13 @@ export async function run(ctx: Ctx): Promise<void> {
|
|||
try { for (const n of (await runScan(ctx.loaded.root, { config: ctx.loaded.path })).report.notes) if (n.startsWith('scan.ignore[')) note(n); } catch (e) { note(`scan.ignore not checked: ${(e as Error).message}`); }
|
||||
}
|
||||
if (config.apple && !config.app.copyright?.trim()) problems.push(COPYRIGHT_MISSING);
|
||||
// the App Review demo account must work on the live backend: a capture sign-in against a local stack that uses it
|
||||
// means local-only credentials are (or will be) stored where review-details sends them to App Review
|
||||
{ const cap = (config as { shots?: { capture?: { baseUrl?: string; auth?: { request?: { url?: string } } } } }).shots?.capture;
|
||||
const authText = JSON.stringify(cap?.auth ?? {});
|
||||
const local = /\b(localhost|127\.0\.0\.1|0\.0\.0\.0|\[::1\]|[a-z0-9-]+\.(localhost|test|local))\b/i;
|
||||
if (/cred:reviewDemoAccount/.test(authText) && (local.test(cap?.baseUrl ?? '') || local.test(cap?.auth?.request?.url ?? '')))
|
||||
note('shots.capture.auth signs in to a local stack with reviewDemoAccount, the account App Review gets from apple review-details: put the local demo sign-in in captureAuth in .storebound/credentials.json and use ${cred:<name>}'); }
|
||||
const duo = iphoneDuoNote({ apple: !!config.apple, duo: !!config.apple?.iphoneDuo, play: !!config.play });
|
||||
if (duo?.level === 'info') { hints.push(duo.msg); log('check', `hint: ${duo.msg}`); } else if (duo) note(duo.msg);
|
||||
const creative = creativeNote(config, ctx.loaded.resolve(config.renders ?? config.shots?.out ?? 'store/renders'));
|
||||
|
|
|
|||
|
|
@ -101,7 +101,10 @@ export async function importConfigModule(path: string): Promise<any> {
|
|||
async function withoutTypeStripWarning<T>(f: () => Promise<T>): Promise<T> {
|
||||
const emit = process.emitWarning;
|
||||
process.emitWarning = ((w: string | Error, ...rest: unknown[]) => {
|
||||
if (/Type Stripping|type stripping/i.test(String(typeof w === 'string' ? w : w.message))) return;
|
||||
// also Node's MODULE_TYPELESS_PACKAGE_JSON ("Reparsing as ES module") for a .ts config in a CommonJS package:
|
||||
// the config is ours to load, the app need not add "type": "module"
|
||||
const text = `${String(typeof w === 'string' ? w : w.message)} ${rest.map(r => (typeof r === 'object' && r ? JSON.stringify(r) : String(r))).join(' ')}`;
|
||||
if (/Type Stripping|type stripping|Reparsing as ES module|MODULE_TYPELESS_PACKAGE_JSON/i.test(text)) return;
|
||||
return (emit as (...a: unknown[]) => void).call(process, w, ...rest);
|
||||
}) as typeof process.emitWarning;
|
||||
try { return await f(); } finally { process.emitWarning = emit; }
|
||||
|
|
|
|||
|
|
@ -197,10 +197,13 @@ Key screens behind a login (`source: 'web'`): capture against a **local or demo
|
|||
demo account. Never real users' data in store screenshots. The same frames feed both stores (App Store and Google
|
||||
Play), so one sign-in setup covers both. Two ways to sign in, set in `shots.capture.auth`:
|
||||
|
||||
- **Sign-in request**: `{ request: { url: '/api/login', method: 'POST', body: { email: '${cred:reviewDemoAccount.username}',
|
||||
password: '${cred:reviewDemoAccount.password}' } } }`. It runs once per browser context before its first shot, and
|
||||
the context keeps the cookies. `${cred:NAME}` reads `.storebound/credentials.json` (`reviewDemoAccount.username` /
|
||||
`.password`, also from REVIEW_DEMO_USER / REVIEW_DEMO_PASSWORD, or any key under `captureAuth`). `${env:NAME}`
|
||||
- **Sign-in request**: `{ request: { url: '/api/login', method: 'POST', body: { email: '${cred:email}',
|
||||
password: '${cred:password}' } } }` with `captureAuth: { email, password }` in `.storebound/credentials.json`. It
|
||||
runs once per browser context before its first shot, and the context keeps the cookies. `${cred:NAME}` reads
|
||||
`captureAuth.NAME` (or `reviewDemoAccount.username` / `.password`, also from REVIEW_DEMO_USER / REVIEW_DEMO_PASSWORD).
|
||||
Keep the two apart: `reviewDemoAccount` is the account `apple review-details` sends to App Review and must work on
|
||||
the live backend; a local demo stack's sign-in belongs in `captureAuth`. `check` warns when a capture against
|
||||
localhost uses `reviewDemoAccount`. `${env:NAME}`
|
||||
reads the environment. A password-, token- or key-like field with a literal value is refused. A status outside
|
||||
2xx/3xx stops the capture and shows the status, never the values.
|
||||
- **Saved session**: `{ storageState: '.storebound/auth.json' }`, made by `storebound shots login [--url <url>]`. It
|
||||
|
|
|
|||
15
tests/capture-review-account.test.ts
Normal file
15
tests/capture-review-account.test.ts
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
// The App Review demo account (reviewDemoAccount, sent by apple review-details) must work on the live backend: a
|
||||
// capture sign-in against a local stack that uses it gets a check note (a session nearly stored local-only creds there).
|
||||
import { afterEach, expect, test } from 'bun:test';
|
||||
import { run as check } from '../cli/check';
|
||||
import { BASE, capture, jsonOut, project, restore } from './helpers/store-mock';
|
||||
|
||||
afterEach(restore);
|
||||
const withAuth = (baseUrl: string, ref: string) => ({ ...BASE, play: undefined, shots: { capture: { baseUrl, auth: { request: { url: '/api/login', method: 'POST', body: { email: `\${cred:${ref}}`, password: `\${cred:${ref.replace('username', 'password').replace('email', 'password')}}` } } } } } }) as typeof BASE;
|
||||
const notes = async (cfg: typeof BASE) => { const p = project(cfg, { '.gitignore': '.storebound/\n' }); const j = jsonOut((await capture(() => check(p.ctx(['--json'], ['json'])))).out); return JSON.stringify(j); };
|
||||
|
||||
test('local capture with reviewDemoAccount gets a note; captureAuth or a remote stack does not', async () => {
|
||||
expect(await notes(withAuth('http://localhost:5173', 'reviewDemoAccount.username'))).toContain('captureAuth');
|
||||
expect(await notes(withAuth('http://localhost:5173', 'email'))).not.toContain('signs in to a local stack');
|
||||
expect(await notes(withAuth('https://staging.example.com', 'reviewDemoAccount.username'))).not.toContain('signs in to a local stack');
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue