Fix city generation retries and remove city-wide economy mechanics
This commit is contained in:
1 parent
85df37c26e
commit
63f0c72ff3
21 files changed
+252
-585
No files matched your search
@@ -24,10 +24,6 @@ try {
|
||||
await page.waitForFunction(()=>document.querySelector('.viewer-top [role=status]')?.textContent.includes('в загруженной области'),null,{timeout:60000});
|
||||
const visibleMs=Math.round(performance.now()-started);
|
||||
await page.waitForFunction(()=>document.querySelector('.room-clock')?.textContent.includes('День'),null,{timeout:10000});
|
||||
await page.waitForFunction(()=>document.querySelector('.room-gameplay')?.textContent.includes('Казна'),null,{timeout:10000});
|
||||
await page.locator('[data-action=meal]').click();
|
||||
await page.waitForFunction(()=>document.querySelector('[data-action=meal]')?.disabled,null,{timeout:5000});
|
||||
await page.waitForFunction(()=>document.querySelector('.room-gameplay')?.textContent.includes('Общий обед'),null,{timeout:15000});
|
||||
await page.getByRole('button',{name:'Пауза',exact:true}).click();
|
||||
await page.waitForFunction(()=>document.querySelector('.room-clock')?.textContent.includes('×0'),null,{timeout:10000});
|
||||
await page.getByRole('button',{name:'1',exact:true}).click();
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
// Run with `node --import tsx scripts/generation-browser-smoke.mjs`.
|
||||
// Uses the same optional Playwright environment variables as browser-smoke.mjs.
|
||||
import { createRequire } from 'node:module';
|
||||
import { resolve } from 'node:path';
|
||||
import assert from 'node:assert/strict';
|
||||
import { create, toBinary } from '@bufbuild/protobuf';
|
||||
import { CityJobSchema } from '../client/generated/city_pb.ts';
|
||||
const require = createRequire(process.env.CITYGEN_BROWSER_MODULES ? resolve(process.env.CITYGEN_BROWSER_MODULES, 'package.json') : import.meta.url);
|
||||
const { chromium } = require('playwright');
|
||||
const browser = await chromium.launch({ headless: true, executablePath: process.env.CITYGEN_BROWSER_EXECUTABLE });
|
||||
try {
|
||||
const page = await browser.newPage();
|
||||
const errors = []; page.on('pageerror', error => errors.push(error.message));
|
||||
let posts = 0, polls = 0, failed = false;
|
||||
await page.route('**/api/cities/jobs**', async route => {
|
||||
if (route.request().method() === 'POST') posts++;
|
||||
else polls++;
|
||||
const job = create(CityJobSchema, { id: 'resume-test', cityId: 'test', status: failed ? 'failed' : 'running', stage: 'Повтор Overpass', error: failed ? 'Overpass временно недоступен' : '' });
|
||||
await route.fulfill({ contentType: 'application/x-protobuf', body: Buffer.from(toBinary(CityJobSchema, job)) });
|
||||
});
|
||||
const url = `${process.env.CITYGEN_TEST_URL || 'http://127.0.0.1:3000'}/?create-city&job=resume-test`;
|
||||
await page.goto(url);
|
||||
await page.getByText('Повтор Overpass…', { exact: true }).waitFor();
|
||||
await page.reload();
|
||||
await page.getByText('Повтор Overpass…', { exact: true }).waitFor();
|
||||
await page.getByRole('button', { name: 'Закрыть ожидание', exact: true }).click();
|
||||
await page.locator('.overlay').waitFor({ state: 'hidden' });
|
||||
await page.getByRole('button', { name: 'Сгенерировать', exact: true }).click();
|
||||
await page.getByText('Повтор Overpass…', { exact: true }).waitFor();
|
||||
failed = true;
|
||||
await page.locator('.err').filter({ hasText: 'Overpass временно недоступен' }).waitFor();
|
||||
assert.equal(new URL(page.url()).searchParams.has('job'), false);
|
||||
assert.equal(posts, 0, 'reload and resume must not create another job');
|
||||
assert.ok(polls >= 3);
|
||||
assert.deepEqual(errors, []);
|
||||
console.log(JSON.stringify({ generationResume: 'passed', posts, polls }));
|
||||
} finally { await browser.close(); }
|
||||
@@ -27,7 +27,7 @@ test('times out a hanging request and tries the next server', async (t) => {
|
||||
return ++calls === 1 ? pending(init.signal!) : Promise.resolve(ok());
|
||||
});
|
||||
const result = fetchOverpass(bbox);
|
||||
t.mock.timers.tick(45_000);
|
||||
t.mock.timers.tick(90_000);
|
||||
assert.deepEqual(await result, elements);
|
||||
assert.equal(calls, 2);
|
||||
});
|
||||
@@ -41,7 +41,7 @@ test('timeout also covers downloading the response body', async (t) => {
|
||||
});
|
||||
const result = fetchOverpass(bbox);
|
||||
await Promise.resolve();
|
||||
t.mock.timers.tick(45_000);
|
||||
t.mock.timers.tick(90_000);
|
||||
assert.deepEqual(await result, elements);
|
||||
assert.equal(calls, 2);
|
||||
});
|
||||
@@ -76,11 +76,18 @@ test('reports failure when every server times out', async (t) => {
|
||||
t.mock.timers.enable({ apis: ['setTimeout'] });
|
||||
const fetch = t.mock.method(globalThis, 'fetch', (_url: string, init: RequestInit) => pending(init.signal!));
|
||||
const result = fetchOverpass(bbox);
|
||||
const check = assert.rejects(result, /Таймаут.*45 секунд/);
|
||||
const check = assert.rejects(result, /Таймаут.*90 секунд/);
|
||||
for (let i = 0; i < OVERPASS_ENDPOINTS.length; i++) {
|
||||
t.mock.timers.tick(45_000);
|
||||
t.mock.timers.tick(90_000);
|
||||
await Promise.resolve();
|
||||
}
|
||||
await check;
|
||||
assert.equal(fetch.mock.callCount(), OVERPASS_ENDPOINTS.length);
|
||||
});
|
||||
test('server identifies itself to Overpass rather than using the generic Node user agent', async (t) => {
|
||||
t.mock.method(globalThis, 'fetch', async (_url: string, init: RequestInit) => {
|
||||
assert.match(new Headers(init.headers).get('User-Agent')!, /citygen/);
|
||||
return ok();
|
||||
});
|
||||
assert.deepEqual(await fetchOverpass(bbox), elements);
|
||||
});
|
||||
Reference in new issue
Block a user