Run server acceptance through CI artifacts and clean task temporaries
studio CI and deployment / verify-and-deploy (pull_request) Successful in 8m10s
studio CI and deployment / verify-and-deploy (pull_request) Successful in 8m10s
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
#!/usr/bin/env bash
|
||||
# Run on ces-control after deployment; never starts a preview web server.
|
||||
set -Eeuo pipefail
|
||||
REPO_ROOT=$(git rev-parse --show-toplevel)
|
||||
RESULT_DIR="$REPO_ROOT/artifacts/studio-acceptance"
|
||||
MODE=${1:-verify}
|
||||
[[ "$MODE" == verify || "$MODE" == --diagnose ]] || exit 2
|
||||
WIKI_IMAGE=$(docker inspect --format '{{.Config.Image}}' prompt-waterfall-wiki-1)
|
||||
[[ "$WIKI_IMAGE" =~ ^waterfall-wiki:[0-9a-f]{40}$ ]] || { echo 'Unexpected Wiki image'; exit 1; }
|
||||
TEST_IMAGE="waterfall-wiki-tests:${WIKI_IMAGE#waterfall-wiki:}"
|
||||
docker image inspect "$TEST_IMAGE" >/dev/null
|
||||
mkdir -p "$RESULT_DIR"
|
||||
chown 1000:1000 "$RESULT_DIR"
|
||||
run_api(){
|
||||
local result_root=$1 script=$2; shift 2
|
||||
docker run --rm --volumes-from prompt-waterfall-wiki-1:ro \
|
||||
--mount "type=bind,src=$REPO_ROOT,dst=/delivery,readonly" \
|
||||
--mount "type=bind,src=$result_root,dst=/tmp/studio-library" \
|
||||
-e AUTH_CONFIG_FILE=/auth/config.json -e AUTH_CHECK_BASE_URL=http://8.211.154.134:18131 \
|
||||
--entrypoint node "$TEST_IMAGE" dist/auth-cli.cjs run "/delivery/scripts/$script" "$@"
|
||||
}
|
||||
# Clean only this task's explicitly named legacy temporary directories. Preserve test data via archive.
|
||||
if [[ -f /tmp/studio-library/verification.json ]]; then
|
||||
run_api /tmp/studio-library verify-studio-library.mjs --finalize
|
||||
fi
|
||||
if [[ -d /tmp/studio-library-source ]]; then
|
||||
test -z "$(git -C /tmp/studio-library-source status --porcelain)" || { echo 'Temporary source has unexpected edits; preserved'; exit 1; }
|
||||
git --git-dir=/tmp/studio-library-delivery.git worktree remove /tmp/studio-library-source
|
||||
fi
|
||||
rm -rf /tmp/studio-library-delivery.git /tmp/studio-library-evidence /tmp/studio-library
|
||||
for old_path in /tmp/studio-library-source /tmp/studio-library-delivery.git /tmp/studio-library-evidence /tmp/studio-library; do
|
||||
test ! -e "$old_path" || exit 1
|
||||
done
|
||||
printf '{"legacyTemporaryDirectoriesRemoved":true}\n' > "$RESULT_DIR/cleanup.json"
|
||||
# Always archive only the UUIDs created by this run, including when visual checks fail.
|
||||
finish(){
|
||||
local status=$?
|
||||
trap - EXIT
|
||||
if [[ -f "$RESULT_DIR/verification.json" ]]; then
|
||||
if ! run_api "$RESULT_DIR" verify-studio-library.mjs --finalize; then status=1; fi
|
||||
fi
|
||||
exit "$status"
|
||||
}
|
||||
trap finish EXIT
|
||||
run_api "$RESULT_DIR" verify-studio-library.mjs
|
||||
docker run --rm --volumes-from prompt-waterfall-wiki-1:ro \
|
||||
--mount "type=bind,src=$REPO_ROOT,dst=/delivery,readonly" \
|
||||
--mount "type=bind,src=$RESULT_DIR,dst=/tmp/studio-library" \
|
||||
-e AUTH_CONFIG_FILE=/auth/config.json -e NODE_PATH=/app/node_modules \
|
||||
--entrypoint node "$TEST_IMAGE" /delivery/scripts/verify-studio-visual.cjs "$MODE"
|
||||
@@ -19,7 +19,7 @@ const assert=require('node:assert/strict');
|
||||
const id='ref-'+String(i).padStart(2,'0');await page.goto(base+'/studio/layouts/'+id,{waitUntil:'networkidle'});await page.locator('article.native-layout').screenshot({path:dir+'/'+id+'.png'});
|
||||
const m=await page.locator('article.native-layout').evaluate(el=>({id:el.dataset.layoutId,elements:el.querySelectorAll('[data-element]').length,width:el.clientWidth,height:el.clientHeight,overflow:[...el.querySelectorAll('.native-copy')].filter(e=>e.scrollHeight>e.clientHeight+2||e.scrollWidth>e.clientWidth+2).map(e=>e.closest('[data-element]').dataset.element)}));metrics.push(m);await writeFile(dir+'/metrics.json',JSON.stringify({metrics,images,errors},null,2));
|
||||
}
|
||||
if(!process.argv.includes('--after-layouts'))assert.deepEqual(metrics.filter(m=>m.overflow.length),[],'Default copy must fit every native slot');
|
||||
if(!process.argv.includes('--after-layouts')&&!process.argv.includes('--diagnose'))assert.deepEqual(metrics.filter(m=>m.overflow.length),[],'Default copy must fit every native slot');
|
||||
await page.goto(base+'/studio',{waitUntil:'networkidle'});assert.equal(await page.locator('.library-item').count(),27);await page.screenshot({path:dir+'/catalog-desktop.png',fullPage:true});
|
||||
const verify=JSON.parse(await readFile('/tmp/studio-library/verification.json','utf8'));
|
||||
for(const d of verify.results){await page.goto(base+d.url,{waitUntil:'networkidle'});assert.equal(await page.locator('img').count(),1);const current=await page.locator('img').evaluate(img=>({src:img.currentSrc,complete:img.complete,width:img.naturalWidth}));assert.ok(current.complete&¤t.width>0);assert.equal(new URL(current.src).pathname,'/api/preview');await page.locator('article.native-layout').screenshot({path:dir+'/'+d.layoutId+'-saved.png'});
|
||||
@@ -28,9 +28,9 @@ const assert=require('node:assert/strict');
|
||||
for(const slug of ['learning-skills-template','layout-selection']){await page.goto(base+'/studio/ideas/'+slug,{waitUntil:'networkidle'});await page.screenshot({path:dir+'/tool-'+slug+'.png',fullPage:true})}
|
||||
await page.setViewportSize({width:390,height:844});await page.goto(base+'/studio',{waitUntil:'networkidle'});assert.ok(await page.evaluate(()=>document.documentElement.scrollWidth<=innerWidth));await page.screenshot({path:dir+'/catalog-mobile.png',fullPage:true});
|
||||
await page.goto(base+verify.results[0].url,{waitUntil:'networkidle'});await page.screenshot({path:dir+'/standard-mobile.png',fullPage:true});
|
||||
await page.goto(base+'/categories?category='+encodeURIComponent('文档入口'),{waitUntil:'domcontentloaded',timeout:60000});await page.getByRole('navigation',{name:'系统标签分类',exact:true}).waitFor({state:'visible'});await page.screenshot({path:dir+'/document-entries.png',fullPage:true});
|
||||
await page.goto(base+'/categories?category='+encodeURIComponent('文档入口'),{waitUntil:'domcontentloaded',timeout:60000});await page.getByRole('navigation',{name:'系统标签分类',exact:true}).waitFor({state:'visible'});assert.equal(await page.locator('.discovery-card').count(),3);await page.waitForFunction(()=>Array.from(document.querySelectorAll('.discovery-card img')).every(img=>img.complete&&img.naturalWidth>0),null,{timeout:60000});await page.screenshot({path:dir+'/document-entries.png',fullPage:true});
|
||||
await writeFile(dir+'/metrics.json',JSON.stringify({metrics,images,errors},null,2));
|
||||
assert.equal(images.filter(r=>new URL(r.path,base).pathname.startsWith('/api/media/')).length,0,'Display must never fetch originals');assert.equal(errors.length,0,JSON.stringify(errors));for(const image of images){if(new URL(image.path,base).pathname==='/brand-mark.svg'){assert.equal(image.status,200);assert.match(image.type,/image\/svg\+xml/);continue;}assert.equal(new URL(image.path,base).pathname,'/api/preview');assert.equal(image.status,200);assert.equal(image.type,'image/webp');assert.ok(image.bytes>0&&image.bytes<=220000)}
|
||||
assert.equal(images.filter(r=>new URL(r.path,base).pathname.startsWith('/api/media/')).length,0,'Display must never fetch originals');if(!process.argv.includes('--diagnose'))assert.equal(errors.length,0,JSON.stringify(errors));for(const image of images){if(new URL(image.path,base).pathname==='/brand-mark.svg'){assert.equal(image.status,200);assert.match(image.type,/image\/svg\+xml/);continue;}assert.equal(new URL(image.path,base).pathname,'/api/preview');assert.equal(image.status,200);assert.equal(image.type,'image/webp');assert.ok(image.bytes>0&&image.bytes<=220000)}
|
||||
await writeFile(dir+'/metrics.json',JSON.stringify({metrics,images,errors},null,2));await browser.close();
|
||||
console.log(JSON.stringify({pages:27,errors:errors.length,displayImages:images.length,originalImageRequests:0,overflow:metrics.filter(m=>m.overflow.length)}));
|
||||
console.log(JSON.stringify({diagnostic:process.argv.includes('--diagnose'),pages:27,errors:errors.length,displayImages:images.length,originalImageRequests:0,overflow:metrics.filter(m=>m.overflow.length)}));
|
||||
})().catch(e=>{console.error(e.message);process.exit(1)});
|
||||
|
||||
Reference in New Issue
Block a user