82 lines
4.6 KiB
JavaScript
82 lines
4.6 KiB
JavaScript
// Optional browser acceptance against the real Worker, never an API mock.
|
|
// Start npm start first. Set TYPY_BASE_URL to verify a deployment.
|
|
import assert from 'node:assert/strict';
|
|
import {createRequire} from 'node:module';
|
|
import {writeFile, mkdir} from 'node:fs/promises';
|
|
const require = createRequire(import.meta.url);
|
|
const {chromium} = require(process.env.CODEX_PRIMARY_RUNTIME_NODE_MODULES
|
|
? process.env.CODEX_PRIMARY_RUNTIME_NODE_MODULES + '/playwright' : 'playwright');
|
|
const base = (process.env.TYPY_BASE_URL || 'http://127.0.0.1:8787').replace(/\/$/, '');
|
|
const browser = await chromium.launch({executablePath:process.env.CHROME || chromium.executablePath(),headless:true,args:['--no-sandbox']});
|
|
const errors = [];
|
|
try {
|
|
const page = await browser.newPage({viewport:{width:1440,height:1000}});
|
|
page.on('pageerror',error=>errors.push(error.message));
|
|
await page.goto(base + '/');
|
|
await page.locator('#word[data-word]').waitFor();
|
|
await page.locator('[data-mode=endless]').click();
|
|
await page.locator('#source-open').click();
|
|
await page.locator('#tab-paste').click();
|
|
const words = 'one quiet morning the river moves through the city with a gentle rhythm'.split(' ');
|
|
await page.locator('#paste-input').fill(words.join(' '));
|
|
await page.locator('#source-paste button[type=submit]').click();
|
|
for (const word of words.slice(0,8)) await page.keyboard.type(word + ' ',{delay:35});
|
|
await page.locator('#finish-run').click();
|
|
await page.locator('#result-panel').waitFor({state:'visible'});
|
|
const score = await page.locator('#result-wpm').textContent();
|
|
await page.locator('#share-button').click();
|
|
await page.locator('#share-name').fill('typy check');
|
|
await page.locator('#save-result').click();
|
|
await page.locator('#share-ready').waitFor({state:'visible'});
|
|
const resultUrl = await page.locator('#share-url').inputValue();
|
|
const resultResponse = await page.request.get(resultUrl.replace('/r/','/api/results/'));
|
|
assert.equal(resultResponse.status(),200);
|
|
const saved = await resultResponse.json();
|
|
assert.deepEqual(saved.run.words,words);
|
|
assert.equal(saved.run.stats.completedWords,8);
|
|
assert.equal(saved.run.stats.accuracy,100);
|
|
assert.equal(String(Math.round(saved.run.stats.wpm)),score);
|
|
assert.ok(saved.run.events.every(event=>Object.keys(event).sort().join(',') === 'index,t,type'));
|
|
await page.goto(resultUrl);
|
|
await page.locator('#result-panel').waitFor({state:'visible'});
|
|
const og = await page.locator('meta[property="og:image"]').getAttribute('content');
|
|
const imageResponse = await page.request.get(og);
|
|
const imageBytes = await imageResponse.body();
|
|
assert.equal(imageResponse.status(),200);
|
|
assert.equal(imageBytes.readUInt32BE(16),1200);
|
|
assert.equal(imageBytes.readUInt32BE(20),630);
|
|
assert.ok(imageBytes.subarray(0,8).equals(Buffer.from([137,80,78,71,13,10,26,10])));
|
|
await page.locator('#replay-button').click();
|
|
await page.locator('#replay-controls').waitFor({state:'visible'});
|
|
await page.locator('#replay-play').click();
|
|
const midpoint = Math.floor(saved.run.durationMs / 20) * 10;
|
|
await page.locator('#replay-scrubber').fill(String(midpoint));
|
|
await page.locator('#replay-scrubber').dispatchEvent('input');
|
|
const replayWord = await page.locator('#word').getAttribute('data-word');
|
|
assert.ok(words.includes(replayWord));
|
|
await page.locator('#replay-back').click();
|
|
await page.locator('#race-button').click();
|
|
await page.locator('#ghost-race').waitFor({state:'visible'});
|
|
assert.ok(page.url().includes('/race/'));
|
|
assert.equal(await page.locator('#word').getAttribute('data-word'),words[0]);
|
|
const health = await (await page.request.get(base + '/api/health')).json();
|
|
assert.equal(health.ok,true);
|
|
const daily1 = await (await page.request.get(base + '/api/daily')).json();
|
|
const daily2 = await (await page.request.get(base + '/api/daily')).json();
|
|
assert.deepEqual(daily1.words,daily2.words);
|
|
assert.equal(daily1.words.length,300);
|
|
assert.deepEqual(errors,[]);
|
|
const report = {
|
|
checkedAt:new Date().toISOString(),base,health,score,resultUrl,
|
|
storedWords:saved.run.words.length,storedEvents:saved.run.events.length,
|
|
replayWord,raceUrl:page.url(),ghostVisible:true,
|
|
og:{status:imageResponse.status(),bytes:imageBytes.length,width:1200,height:630},
|
|
dailySame:true,dailyWords:daily1.words.length,errors
|
|
};
|
|
await mkdir('evidence',{recursive:true});
|
|
const name = base.includes('127.0.0.1') ? 'local' : 'live';
|
|
await writeFile('evidence/' + name + '-integration.json',JSON.stringify(report,null,2) + '\n');
|
|
await writeFile('evidence/' + name + '-result.png',imageBytes);
|
|
console.log(JSON.stringify(report,null,2));
|
|
} finally { await browser.close(); }
|