apple screenshots: iPhone Duo through the App Asset Library (IPHONE_DUO placement group, APP_SCREENSHOT), pitfall 130

This commit is contained in:
CRTkafa 2026-11-08 14:19:12 +07:00
parent b1043f5d79
commit 73a962fbdc
10 changed files with 174 additions and 32 deletions

View file

@ -1,12 +1,13 @@
import { describe, expect, test } from 'bun:test';
import { displaySets, skippedDuoSets } from '../cli/apple/screenshots';
import { displaySets, duoDirs } from '../cli/apple/screenshots';
import { duoGroups, duoUpToDate } from '../cli/apple/duo-library';
import { appleRules } from '../cli/lib/validate-rules';
import { checkCreate, createExperimentReq, defaultName, experimentFromApi, pickExperiment, planTreatmentLocales, planTreatments, startStopReq } from '../cli/lib/ppo';
import { validateConfig } from '../cli/lib/config';
import { FORBIDDEN_ARGS, TOOLS, toArgv, validateInput } from '../cli/mcp-tools';
import { requiredSets } from '../cli/shots/report';
import { defaultSizes, SIZES } from '../cli/shots/lib';
import { checkImage, IMAGE_SPECS, imageInfo, IPHONE_DUO_DISPLAY, IPHONE_DUO_NOT_IN_API, iphoneDuoNote } from '../cli/shots/spec';
import { checkImage, IMAGE_SPECS, imageInfo, IPHONE_DUO_DISPLAY, iphoneDuoNote } from '../cli/shots/spec';
import { png } from './fixtures';
describe('product page optimization', () => {
@ -91,12 +92,21 @@ describe('iPhone Duo (foldable) sizes', () => {
expect(checkImage(imageInfo(png(2007, 2853)), 'iphone-duo-outer').map(i => i.code)).toEqual(['size']);
expect(checkImage(imageInfo(png(2007, 2853, { colorType: 6 })), 'iphone-duo-inner').map(i => i.code)).toEqual(['alpha']);
});
test('upload: no API display type yet, so the sets are skipped with the message', () => {
test('upload: no ScreenshotDisplayType; Duo goes through the App Asset Library (IPHONE_DUO group)', () => {
expect(Object.values(IPHONE_DUO_DISPLAY).every(t => t === null)).toBe(true);
expect(Object.keys(displaySets({ iphoneDuo: true }))).not.toContain('iphone-duo-outer');
expect(skippedDuoSets({})).toBeNull();
expect(skippedDuoSets({ iphoneDuo: true })).toEqual({ dirs: ['iphone-duo-outer', 'iphone-duo-inner'], msg: expect.stringContaining(`iphone-duo-outer, iphone-duo-inner: ${IPHONE_DUO_NOT_IN_API}. Add them in App Store Connect > the iOS version page > App Previews and Screenshots > iPhone Duo: https://`) });
expect(skippedDuoSets({ iphoneDuo: true, appId: '1234567890' })!.msg).toContain('/apps/1234567890/distribution/ios/version/inflight');
expect(duoDirs({})).toEqual([]);
expect(duoDirs({ iphoneDuo: true })).toEqual(['iphone-duo-outer', 'iphone-duo-inner']);
const ref = [{ attributes: { placementProfileGroups: [
{ placementProfileGroupId: 'g-67', platform: 'IOS', displayClassId: 'IPHONE_DYNAMIC_ISLAND_LARGE_DISPLAY' },
{ placementProfileGroupId: 'g-duo', platform: 'IOS', displayClassId: 'IPHONE_DUO' },
{ placementProfileGroupId: 'g-duo', platform: 'IOS', displayClassId: 'IPHONE_DUO' },
{ placementProfileGroupId: 'g-mac', platform: 'MAC_OS', displayClassId: 'IPHONE_DUO' }] } }];
expect(duoGroups(ref)).toEqual(['g-duo']);
expect(duoGroups([])).toEqual([]);
expect(duoUpToDate(['a', 'b'], ['a', 'b'])).toBe(true);
expect(duoUpToDate(['b', 'a'], ['a', 'b'])).toBe(false);
expect(duoUpToDate(['a', undefined], ['a', 'b'])).toBe(false);
});
test('check / validate note: info before April 2027, never a blocker; points Play to the tablet sets', () => {
const before = new Date('2026-10-18'), after = new Date('2027-04-02');
@ -106,7 +116,7 @@ describe('iPhone Duo (foldable) sizes', () => {
expect(n.level).toBe('info');
expect(n.msg).toContain('optional now, required from April 2027 for iOS 27.1 SDK builds');
expect(n.msg).toContain('tablet screenshots');
expect(n.msg).toContain('the App Store Connect console takes Duo screenshots and previews, the API does not yet');
expect(n.msg).toContain('apple screenshots uploads them through the App Asset Library');
expect(iphoneDuoNote({ apple: true, duo: false, today: after })!.level).toBe('warn');
const base = { version: null, build: null, locales: [], expectedLocales: [], requiredDisplayTypes: [], reviewDetail: null, ageRating: null, priceSchedule: true, availability: true, iaps: [], expectedProducts: [], privacyUrl: { url: 'https://example.com/privacy', status: 200 } };
const f = appleRules({ ...base, today: before } as unknown as Parameters<typeof appleRules>[0]).find(x => x.code === 'screenshots-duo')!;